[PATCH 5/6] pipeio: Add fwts_pipe_readwrite

Jeremy Kerr jk at ozlabs.org
Fri Apr 22 05:41:11 UTC 2016


This change adds a function to process input & output data of a process
opened by fwts_pipe_open_rw(). We add support for the input file
descriptor, and add poll() to allow reads & writes to the child process
(and use non-blocking IO on the file descriptors to make this possible).

We then implement the existing fwts_pipe_read() as a base-case of this
new function, by not providing input data to write.

Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
---
 src/lib/include/fwts_pipeio.h |   3 ++
 src/lib/src/fwts_pipeio.c     | 107 ++++++++++++++++++++++++++++++++++--------
 2 files changed, 90 insertions(+), 20 deletions(-)

diff --git a/src/lib/include/fwts_pipeio.h b/src/lib/include/fwts_pipeio.h
index e2d498a..7f9aaf4 100644
--- a/src/lib/include/fwts_pipeio.h
+++ b/src/lib/include/fwts_pipeio.h
@@ -34,6 +34,9 @@ int   fwts_pipe_open_ro(const char *command, pid_t *childpid, int *fd);
 int   fwts_pipe_open_rw(const char *command, pid_t *childpid, int *in_fd,
 		int *out_fd);
 int   fwts_pipe_read(const int fd, char **out_buf, ssize_t *out_len);
+int   fwts_pipe_readwrite(
+		const int in_fd, const char *in_buf, const size_t in_len,
+		const int out_fd, char **out_buf, ssize_t *out_len);
 int   fwts_pipe_close(const int fd, const pid_t pid);
 int   fwts_pipe_exec(const char *command, fwts_list **list, int *status);
 int   fwts_exec(const char *command, int *status);
diff --git a/src/lib/src/fwts_pipeio.c b/src/lib/src/fwts_pipeio.c
index bb51515..a741477 100644
--- a/src/lib/src/fwts_pipeio.c
+++ b/src/lib/src/fwts_pipeio.c
@@ -32,6 +32,7 @@
 #include <paths.h>
 
 #include <sys/param.h>
+#include <sys/poll.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <errno.h>
@@ -128,51 +129,117 @@ int fwts_pipe_open_ro(const char *command, pid_t *childpid, int *fd)
 	return fwts_pipe_open_rw(command, childpid, NULL, fd);
 }
 
+static int fwts_pipeio_set_nonblock(const int fd)
+{
+	int flags;
+	if (fd < 0)
+		return 0;
+	flags = fcntl(fd, F_GETFL, 0);
+	flags |= O_NONBLOCK;
+	return !!fcntl(fd, F_SETFL, flags);
+}
+
 /*
- *  fwts_pipe_read()
- *	read output from fwts_pipe_open_ro(), *out_buf is populated with
- *	returned data (allocated, must be free()-ed after use), and length in
- *	*out_len.
+ *  fwts_pipe_readwrite()
+ *	send input to and read output from fwts_pipe_open_rw(), in_len bytes
+ *	of in_buf are written to the pipe, and data is read into *out_buf,
+ *	*out_len indicating output length. *out_buf is allocated, and
+ *	must be free()-ed after use.
  *	Returns non-zero on failure.
  */
-int fwts_pipe_read(const int fd, char **out_buf, ssize_t *out_len)
+int fwts_pipe_readwrite(
+		const int in_fd, const char *in_buf, const size_t in_len,
+		const int out_fd, char **out_buf, ssize_t *out_len)
 {
+	struct pollfd pollfds[2];
+	size_t in_size = in_len;
+	ssize_t out_size = 0;
 	char *ptr = NULL;
 	char buffer[8192];
-	ssize_t size = 0;
+
 	*out_len = 0;
 
-	ptr = NULL;
+	pollfds[0].fd = out_fd;
+	pollfds[0].events = POLLIN;
+	pollfds[1].fd = in_fd;
+	pollfds[1].events = POLLOUT;
+
+	/* we need non-blocking IO */
+	if (fwts_pipeio_set_nonblock(in_fd))
+		return -1;
+
+	if (fwts_pipeio_set_nonblock(out_fd))
+		return -1;
 
 	for (;;) {
-		ssize_t n = read(fd, buffer, sizeof(buffer));
+		ssize_t n;
 		char *tmp;
+		int rc;
+
+		if (in_size == 0 || in_fd < 0 || in_buf == NULL)
+			pollfds[1].events = 0;
 
-		if (n == 0)
+		rc = poll(pollfds, 2, -1);
+		if (rc < 0)
 			break;
-		if (n < 0) {
-			if (errno != EINTR && errno != EAGAIN) {
+
+		if (pollfds[0].revents) {
+			n = read(out_fd, buffer, sizeof(buffer));
+
+			if (n == 0)
+				break;
+			if (n < 0) {
+				if (errno != EINTR && errno != EAGAIN) {
+					free(ptr);
+					return -1;
+				}
+				continue;
+			}
+
+			if ((tmp = realloc(ptr, out_size + n + 1)) == NULL) {
 				free(ptr);
 				return -1;
 			}
-			continue;
+			ptr = tmp;
+			memcpy(ptr + out_size, buffer, n);
+			out_size += n;
+			*(ptr+out_size) = 0;
 		}
 
-		if ((tmp = realloc(ptr, size + n + 1)) == NULL) {
-			free(ptr);
-			return -1;
+		if (pollfds[1].revents) {
+			n = write(in_fd, in_buf, in_size);
+
+			if (n < 0) {
+				if (errno != EINTR && errno != EAGAIN) {
+					free(ptr);
+					return -1;
+				}
+				continue;
+			}
+
+			in_buf += n;
+			in_size -= n;
 		}
-		ptr = tmp;
-		memcpy(ptr + size, buffer, n);
-		size += n;
-		*(ptr+size) = 0;
+
 	}
-	*out_len = size;
+
+	*out_len = out_size;
 	*out_buf = ptr;
 	return 0;
 }
 
 /*
+ *  fwts_pipe_read()
+ *	read output from fwts_pipe_open_ro(), *length is
+ *	set to the number of chars read and we return
+ *	a buffer of read data.
+ */
+int fwts_pipe_read(const int fd, char **out_buf, ssize_t *out_len)
+{
+	return fwts_pipe_readwrite(-1, NULL, 0, fd, out_buf, out_len);
+}
+
+/*
  *  fwts_pipe_close()
  *	close fd, wait for child of given pid to exit
  */
-- 
2.5.0




More information about the fwts-devel mailing list