summaryrefslogtreecommitdiff
path: root/pipe.c
diff options
context:
space:
mode:
authorMartin Pool <mbp@samba.org>2002-04-08 04:10:20 +0000
committerMartin Pool <mbp@samba.org>2002-04-08 04:10:20 +0000
commitb35d0d8e9ae9c5407c9f781b545f8a66b9caa9d0 (patch)
treeca00ceac1d12f7d7494ab5120e508e99db26b2cc /pipe.c
parentc948e309f27c3edaef8a5a4dfc04e0da98944c97 (diff)
downloadrsync-b35d0d8e9ae9c5407c9f781b545f8a66b9caa9d0.tar.gz
Split code out into separate files and remove some global variables to
reduce symbol dependencies between files and therefore make it easier to write unit tests. The diff is large, but the actual code changes are pretty small.
Diffstat (limited to 'pipe.c')
-rw-r--r--pipe.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/pipe.c b/pipe.c
new file mode 100644
index 00000000..e2e88ec3
--- /dev/null
+++ b/pipe.c
@@ -0,0 +1,127 @@
+#include "rsync.h"
+
+/**
+ * Create a child connected to use on stdin/stdout.
+ *
+ * This is derived from CVS code
+ *
+ * Note that in the child STDIN is set to blocking and STDOUT
+ * is set to non-blocking. This is necessary as rsh relies on stdin being blocking
+ * and ssh relies on stdout being non-blocking
+ *
+ * If blocking_io is set then use blocking io on both fds. That can be
+ * used to cope with badly broken rsh implementations like the one on
+ * Solaris.
+ **/
+pid_t piped_child(char **command, int *f_in, int *f_out)
+{
+ pid_t pid;
+ int to_child_pipe[2];
+ int from_child_pipe[2];
+ extern int blocking_io;
+
+ if (verbose >= 2) {
+ print_child_argv(command);
+ }
+
+ if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
+ rprintf(FERROR, "pipe: %s\n", strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+
+ pid = do_fork();
+ if (pid == -1) {
+ rprintf(FERROR, "fork: %s\n", strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+ if (pid == 0) {
+ extern int orig_umask;
+ if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
+ close(to_child_pipe[1]) < 0 ||
+ close(from_child_pipe[0]) < 0 ||
+ dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
+ rprintf(FERROR, "Failed to dup/close : %s\n",
+ strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+ if (to_child_pipe[0] != STDIN_FILENO)
+ close(to_child_pipe[0]);
+ if (from_child_pipe[1] != STDOUT_FILENO)
+ close(from_child_pipe[1]);
+ umask(orig_umask);
+ set_blocking(STDIN_FILENO);
+ if (blocking_io) {
+ set_blocking(STDOUT_FILENO);
+ }
+ execvp(command[0], command);
+ rprintf(FERROR, "Failed to exec %s : %s\n",
+ command[0], strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+ if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
+ rprintf(FERROR, "Failed to close : %s\n", strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+ *f_in = from_child_pipe[0];
+ *f_out = to_child_pipe[1];
+
+ return pid;
+}
+
+pid_t local_child(int argc, char **argv,int *f_in,int *f_out,
+ int (*child_main)(int, char **))
+{
+ pid_t pid;
+ int to_child_pipe[2];
+ int from_child_pipe[2];
+ extern int read_batch; /* dw */
+
+ if (fd_pair(to_child_pipe) < 0 ||
+ fd_pair(from_child_pipe) < 0) {
+ rprintf(FERROR,"pipe: %s\n",strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+
+ pid = do_fork();
+ if (pid == -1) {
+ rprintf(FERROR,"fork: %s\n",strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+ if (pid == 0) {
+ extern int am_sender;
+ extern int am_server;
+
+ am_sender = read_batch ? 0 : !am_sender;
+ am_server = 1;
+
+ if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
+ close(to_child_pipe[1]) < 0 ||
+ close(from_child_pipe[0]) < 0 ||
+ dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
+ rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+ if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
+ if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
+ child_main(argc, argv);
+ }
+
+ if (close(from_child_pipe[1]) < 0 ||
+ close(to_child_pipe[0]) < 0) {
+ rprintf(FERROR,"Failed to close : %s\n",strerror(errno));
+ exit_cleanup(RERR_IPC);
+ }
+
+ *f_in = from_child_pipe[0];
+ *f_out = to_child_pipe[1];
+
+ return pid;
+}
+
+