if the remote shell is rsh then use blocking IO
[rsync/rsync.git] / util.c
diff --git a/util.c b/util.c
index 4382300..d8d4e9d 100644 (file)
--- a/util.c
+++ b/util.c
 
 extern int verbose;
 
-/* this is taken from CVS */
+
+/****************************************************************************
+Set a fd into nonblocking mode
+****************************************************************************/
+void set_nonblocking(int fd)
+{
+       int val;
+
+       if((val = fcntl(fd, F_GETFL, 0)) == -1)
+               return;
+       if (!(val & NONBLOCK_FLAG)) {
+               val |= NONBLOCK_FLAG;
+               fcntl(fd, F_SETFL, val);
+       }
+}
+
+/****************************************************************************
+Set a fd into blocking mode
+****************************************************************************/
+void set_blocking(int fd)
+{
+       int val;
+
+       if((val = fcntl(fd, F_GETFL, 0)) == -1)
+               return;
+       if (val & NONBLOCK_FLAG) {
+               val &= ~NONBLOCK_FLAG;
+               fcntl(fd, F_SETFL, val);
+       }
+}
+
+
+/* create a file descriptor pair - like pipe() but use socketpair if
+   possible (because of blocking issues on pipes)
+
+   always set non-blocking
+ */
+int fd_pair(int fd[2])
+{
+       int ret;
+
+#if HAVE_SOCKETPAIR
+       ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+#else
+       ret = pipe(fd);
+#endif
+
+       if (ret == 0) {
+               set_nonblocking(fd[0]);
+               set_nonblocking(fd[1]);
+       }
+       
+       return ret;
+}
+
+
+/* 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.
+ */
 int piped_child(char **command,int *f_in,int *f_out)
 {
   int pid;
   int to_child_pipe[2];
   int from_child_pipe[2];
+  extern int blocking_io;
 
-  if (pipe(to_child_pipe) < 0 ||
-      pipe(from_child_pipe) < 0) {
+  if (fd_pair(to_child_pipe) < 0 ||
+      fd_pair(from_child_pipe) < 0) {
     rprintf(FERROR,"pipe: %s\n",strerror(errno));
     exit_cleanup(RERR_IPC);
   }
@@ -59,6 +125,10 @@ int piped_child(char **command,int *f_in,int *f_out)
       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));
@@ -83,8 +153,8 @@ int local_child(int argc, char **argv,int *f_in,int *f_out)
        int to_child_pipe[2];
        int from_child_pipe[2];
 
-       if (pipe(to_child_pipe) < 0 ||
-           pipe(from_child_pipe) < 0) {
+       if (fd_pair(to_child_pipe) < 0 ||
+           fd_pair(from_child_pipe) < 0) {
                rprintf(FERROR,"pipe: %s\n",strerror(errno));
                exit_cleanup(RERR_IPC);
        }