File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / support / savetransfer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, v3_1_2p5, rsync3_0_9p0, RSYNC3_1_0, RSYNC3_0_9, HEAD
rsync

    1: /* This program can record the stream of data flowing to or from a program.
    2:  * This allows it to be used to check that rsync's data that is flowing
    3:  * through a remote shell is not being corrupted (for example).
    4:  *
    5:  * Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]
    6:  * -i  Save the input going to PROGRAM to the OUTPUT_FILE
    7:  * -o  Save the output coming from PROGRAM to the OUTPUT_FILE
    8:  *
    9:  * If you want to capture the flow of data for an rsync command, use one of
   10:  * the following commands (the resulting files should be identical):
   11:  *
   12:  * rsync -av --rsh="savetransfer -i /tmp/to.server ssh"
   13:  *   --rsync-path="savetransfer -i /tmp/from.client rsync" SOURCE DEST
   14:  *
   15:  * rsync -av --rsh="savetransfer -o /tmp/from.server ssh"
   16:  *   --rsync-path="savetransfer -o /tmp/to.client rsync" SOURCE DEST
   17:  *
   18:  * Note that this program aborts after 30 seconds of inactivity, so you'll need
   19:  * to change it if that is not enough dead time for your transfer.  Also, some
   20:  * of the above commands will not notice that the transfer is done (if we're
   21:  * saving the input to a PROGRAM and the PROGRAM goes away:  we won't notice
   22:  * that it's gone unless more data comes in) -- when this happens it will delay
   23:  * at the end of the transfer until the timeout period expires.
   24:  */
   25: 
   26: #include "../rsync.h"
   27: 
   28: #define TIMEOUT_SECONDS 30
   29: 
   30: #ifdef HAVE_SIGACTION
   31: static struct sigaction sigact;
   32: #endif
   33: 
   34: void run_program(char **command);
   35: 
   36: char buf[4096];
   37: int save_data_from_program = 0;
   38: 
   39: int
   40: main(int argc, char *argv[])
   41: {
   42:     int fd_file, len;
   43:     struct timeval tv;
   44:     fd_set fds;
   45: 
   46:     argv++;
   47:     if (--argc && argv[0][0] == '-') {
   48: 	if (argv[0][1] == 'o')
   49: 	    save_data_from_program = 1;
   50: 	else if (argv[0][1] == 'i')
   51: 	    save_data_from_program = 0;
   52: 	else {
   53: 	    fprintf(stderr, "Unknown option: %s\n", argv[0]);
   54: 	    exit(1);
   55: 	}
   56: 	argv++;
   57: 	argc--;
   58:     }
   59:     if (argc < 2) {
   60: 	fprintf(stderr, "Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]\n");
   61: 	fprintf(stderr, "-i  Save the input going to PROGRAM to the OUTPUT_FILE\n");
   62: 	fprintf(stderr, "-o  Save the output coming from PROGRAM to the OUTPUT_FILE\n");
   63: 	exit(1);
   64:     }
   65:     if ((fd_file = open(*argv, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0644)) < 0) {
   66: 	fprintf(stderr, "Unable to write to `%s': %s\n", *argv, strerror(errno));
   67: 	exit(1);
   68:     }
   69:     set_blocking(fd_file);
   70: 
   71:     SIGACTION(SIGPIPE, SIG_IGN);
   72: 
   73:     run_program(argv + 1);
   74: 
   75: #if defined HAVE_SETMODE && O_BINARY
   76:     setmode(STDIN_FILENO, O_BINARY);
   77:     setmode(STDOUT_FILENO, O_BINARY);
   78: #endif
   79:     set_nonblocking(STDIN_FILENO);
   80:     set_blocking(STDOUT_FILENO);
   81: 
   82:     while (1) {
   83: 	FD_ZERO(&fds);
   84: 	FD_SET(STDIN_FILENO, &fds);
   85: 	tv.tv_sec = TIMEOUT_SECONDS;
   86: 	tv.tv_usec = 0;
   87: 	if (!select(STDIN_FILENO+1, &fds, NULL, NULL, &tv))
   88: 	    break;
   89: 	if (!FD_ISSET(STDIN_FILENO, &fds))
   90: 	    break;
   91: 	if ((len = read(STDIN_FILENO, buf, sizeof buf)) <= 0)
   92: 	    break;
   93: 	if (write(STDOUT_FILENO, buf, len) != len) {
   94: 	    fprintf(stderr, "Failed to write data to stdout: %s\n", strerror(errno));
   95: 	    exit(1);
   96: 	}
   97: 	if (write(fd_file, buf, len) != len) {
   98: 	    fprintf(stderr, "Failed to write data to fd_file: %s\n", strerror(errno));
   99: 	    exit(1);
  100: 	}
  101:     }
  102:     return 0;
  103: }
  104: 
  105: void
  106: run_program(char **command)
  107: {
  108:     int pipe_fds[2], ret;
  109:     pid_t pid;
  110: 
  111:     if (pipe(pipe_fds) < 0) {
  112: 	fprintf(stderr, "pipe failed: %s\n", strerror(errno));
  113: 	exit(1);
  114:     }
  115: 
  116:     if ((pid = fork()) < 0) {
  117: 	fprintf(stderr, "fork failed: %s\n", strerror(errno));
  118: 	exit(1);
  119:     }
  120: 
  121:     if (pid == 0) {
  122: 	if (save_data_from_program)
  123: 	    ret = dup2(pipe_fds[1], STDOUT_FILENO);
  124: 	else
  125: 	    ret = dup2(pipe_fds[0], STDIN_FILENO);
  126: 	if (ret < 0) {
  127: 	    fprintf(stderr, "Failed to dup (in child): %s\n", strerror(errno));
  128: 	    exit(1);
  129: 	}
  130: 	close(pipe_fds[0]);
  131: 	close(pipe_fds[1]);
  132: 	set_blocking(STDIN_FILENO);
  133: 	set_blocking(STDOUT_FILENO);
  134: 	execvp(command[0], command);
  135: 	fprintf(stderr, "Failed to exec %s: %s\n", command[0], strerror(errno));
  136: 	exit(1);
  137:     }
  138: 
  139:     if (save_data_from_program)
  140: 	ret = dup2(pipe_fds[0], STDIN_FILENO);
  141:     else
  142: 	ret = dup2(pipe_fds[1], STDOUT_FILENO);
  143:     if (ret < 0) {
  144: 	fprintf(stderr, "Failed to dup (in parent): %s\n", strerror(errno));
  145: 	exit(1);
  146:     }
  147:     close(pipe_fds[0]);
  148:     close(pipe_fds[1]);
  149: }
  150: 
  151: void
  152: set_nonblocking(int fd)
  153: {
  154:     int val;
  155: 
  156:     if ((val = fcntl(fd, F_GETFL, 0)) == -1)
  157: 	return;
  158:     if (!(val & NONBLOCK_FLAG)) {
  159: 	val |= NONBLOCK_FLAG;
  160: 	fcntl(fd, F_SETFL, val);
  161:     }
  162: }
  163: 
  164: void
  165: set_blocking(int fd)
  166: {
  167:     int val;
  168: 
  169:     if ((val = fcntl(fd, F_GETFL, 0)) < 0)
  170: 	return;
  171:     if (val & NONBLOCK_FLAG) {
  172: 	val &= ~NONBLOCK_FLAG;
  173: 	fcntl(fd, F_SETFL, val);
  174:     }
  175: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>