Annotation of embedaddon/rsync/pipe.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Routines used to setup various kinds of inter-process pipes.
! 3: *
! 4: * Copyright (C) 1996-2000 Andrew Tridgell
! 5: * Copyright (C) 1996 Paul Mackerras
! 6: * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
! 7: * Copyright (C) 2004-2009 Wayne Davison
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify
! 10: * it under the terms of the GNU General Public License as published by
! 11: * the Free Software Foundation; either version 3 of the License, or
! 12: * (at your option) any later version.
! 13: *
! 14: * This program is distributed in the hope that it will be useful,
! 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 17: * GNU General Public License for more details.
! 18: *
! 19: * You should have received a copy of the GNU General Public License along
! 20: * with this program; if not, visit the http://fsf.org website.
! 21: */
! 22:
! 23: #include "rsync.h"
! 24:
! 25: extern int am_sender;
! 26: extern int am_server;
! 27: extern int blocking_io;
! 28: extern int filesfrom_fd;
! 29: extern mode_t orig_umask;
! 30: extern char *logfile_name;
! 31: extern struct chmod_mode_struct *chmod_modes;
! 32:
! 33: /**
! 34: * Create a child connected to us via its stdin/stdout.
! 35: *
! 36: * This is derived from CVS code
! 37: *
! 38: * Note that in the child STDIN is set to blocking and STDOUT
! 39: * is set to non-blocking. This is necessary as rsh relies on stdin being blocking
! 40: * and ssh relies on stdout being non-blocking
! 41: *
! 42: * If blocking_io is set then use blocking io on both fds. That can be
! 43: * used to cope with badly broken rsh implementations like the one on
! 44: * Solaris.
! 45: **/
! 46: pid_t piped_child(char **command, int *f_in, int *f_out)
! 47: {
! 48: pid_t pid;
! 49: int to_child_pipe[2];
! 50: int from_child_pipe[2];
! 51:
! 52: if (verbose >= 2)
! 53: print_child_argv("opening connection using:", command);
! 54:
! 55: if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
! 56: rsyserr(FERROR, errno, "pipe");
! 57: exit_cleanup(RERR_IPC);
! 58: }
! 59:
! 60: pid = do_fork();
! 61: if (pid == -1) {
! 62: rsyserr(FERROR, errno, "fork");
! 63: exit_cleanup(RERR_IPC);
! 64: }
! 65:
! 66: if (pid == 0) {
! 67: if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
! 68: close(to_child_pipe[1]) < 0 ||
! 69: close(from_child_pipe[0]) < 0 ||
! 70: dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
! 71: rsyserr(FERROR, errno, "Failed to dup/close");
! 72: exit_cleanup(RERR_IPC);
! 73: }
! 74: if (to_child_pipe[0] != STDIN_FILENO)
! 75: close(to_child_pipe[0]);
! 76: if (from_child_pipe[1] != STDOUT_FILENO)
! 77: close(from_child_pipe[1]);
! 78: umask(orig_umask);
! 79: set_blocking(STDIN_FILENO);
! 80: if (blocking_io > 0)
! 81: set_blocking(STDOUT_FILENO);
! 82: execvp(command[0], command);
! 83: rsyserr(FERROR, errno, "Failed to exec %s", command[0]);
! 84: exit_cleanup(RERR_IPC);
! 85: }
! 86:
! 87: if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) {
! 88: rsyserr(FERROR, errno, "Failed to close");
! 89: exit_cleanup(RERR_IPC);
! 90: }
! 91:
! 92: *f_in = from_child_pipe[0];
! 93: *f_out = to_child_pipe[1];
! 94:
! 95: return pid;
! 96: }
! 97:
! 98: /* This function forks a child which calls child_main(). First,
! 99: * however, it has to establish communication paths to and from the
! 100: * newborn child. It creates two socket pairs -- one for writing to
! 101: * the child (from the parent) and one for reading from the child
! 102: * (writing to the parent). Since that's four socket ends, each
! 103: * process has to close the two ends it doesn't need. The remaining
! 104: * two socket ends are retained for reading and writing. In the
! 105: * child, the STDIN and STDOUT file descriptors refer to these
! 106: * sockets. In the parent, the function arguments f_in and f_out are
! 107: * set to refer to these sockets. */
! 108: pid_t local_child(int argc, char **argv, int *f_in, int *f_out,
! 109: int (*child_main)(int, char*[]))
! 110: {
! 111: pid_t pid;
! 112: int to_child_pipe[2];
! 113: int from_child_pipe[2];
! 114:
! 115: /* The parent process is always the sender for a local rsync. */
! 116: assert(am_sender);
! 117:
! 118: if (fd_pair(to_child_pipe) < 0 ||
! 119: fd_pair(from_child_pipe) < 0) {
! 120: rsyserr(FERROR, errno, "pipe");
! 121: exit_cleanup(RERR_IPC);
! 122: }
! 123:
! 124: pid = do_fork();
! 125: if (pid == -1) {
! 126: rsyserr(FERROR, errno, "fork");
! 127: exit_cleanup(RERR_IPC);
! 128: }
! 129:
! 130: if (pid == 0) {
! 131: am_sender = 0;
! 132: am_server = 1;
! 133: filesfrom_fd = -1;
! 134: chmod_modes = NULL; /* Let the sending side handle this. */
! 135:
! 136: /* Let the client side handle this. */
! 137: if (logfile_name) {
! 138: logfile_name = NULL;
! 139: logfile_close();
! 140: }
! 141:
! 142: if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
! 143: close(to_child_pipe[1]) < 0 ||
! 144: close(from_child_pipe[0]) < 0 ||
! 145: dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
! 146: rsyserr(FERROR, errno, "Failed to dup/close");
! 147: exit_cleanup(RERR_IPC);
! 148: }
! 149: if (to_child_pipe[0] != STDIN_FILENO)
! 150: close(to_child_pipe[0]);
! 151: if (from_child_pipe[1] != STDOUT_FILENO)
! 152: close(from_child_pipe[1]);
! 153: #ifdef ICONV_CONST
! 154: setup_iconv();
! 155: #endif
! 156: child_main(argc, argv);
! 157: }
! 158:
! 159: if (close(from_child_pipe[1]) < 0 ||
! 160: close(to_child_pipe[0]) < 0) {
! 161: rsyserr(FERROR, errno, "Failed to close");
! 162: exit_cleanup(RERR_IPC);
! 163: }
! 164:
! 165: *f_in = from_child_pipe[0];
! 166: *f_out = to_child_pipe[1];
! 167:
! 168: return pid;
! 169: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>