Annotation of embedaddon/rsync/main.c, revision 1.1
1.1 ! misho 1: /*
! 2: * The startup routines, including main(), for rsync.
! 3: *
! 4: * Copyright (C) 1996-2001 Andrew Tridgell <tridge@samba.org>
! 5: * Copyright (C) 1996 Paul Mackerras
! 6: * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
! 7: * Copyright (C) 2003-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: #include "ifuncs.h"
! 25: #include "io.h"
! 26: #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H
! 27: #include <locale.h>
! 28: #endif
! 29:
! 30: extern int verbose;
! 31: extern int dry_run;
! 32: extern int list_only;
! 33: extern int am_root;
! 34: extern int am_server;
! 35: extern int am_sender;
! 36: extern int am_daemon;
! 37: extern int inc_recurse;
! 38: extern int blocking_io;
! 39: extern int remove_source_files;
! 40: extern int need_messages_from_generator;
! 41: extern int kluge_around_eof;
! 42: extern int do_stats;
! 43: extern int got_xfer_error;
! 44: extern int module_id;
! 45: extern int copy_links;
! 46: extern int copy_dirlinks;
! 47: extern int copy_unsafe_links;
! 48: extern int keep_dirlinks;
! 49: extern int preserve_hard_links;
! 50: extern int protocol_version;
! 51: extern int file_total;
! 52: extern int recurse;
! 53: extern int xfer_dirs;
! 54: extern int protect_args;
! 55: extern int relative_paths;
! 56: extern int sanitize_paths;
! 57: extern int curr_dir_depth;
! 58: extern int curr_dir_len;
! 59: extern int module_id;
! 60: extern int rsync_port;
! 61: extern int whole_file;
! 62: extern int read_batch;
! 63: extern int write_batch;
! 64: extern int batch_fd;
! 65: extern int filesfrom_fd;
! 66: extern int connect_timeout;
! 67: extern dev_t filesystem_dev;
! 68: extern pid_t cleanup_child_pid;
! 69: extern unsigned int module_dirlen;
! 70: extern struct stats stats;
! 71: extern char *filesfrom_host;
! 72: extern char *partial_dir;
! 73: extern char *dest_option;
! 74: extern char *basis_dir[MAX_BASIS_DIRS+1];
! 75: extern char *rsync_path;
! 76: extern char *shell_cmd;
! 77: extern char *batch_name;
! 78: extern char *password_file;
! 79: extern char curr_dir[MAXPATHLEN];
! 80: extern struct file_list *first_flist;
! 81: extern struct filter_list_struct daemon_filter_list;
! 82:
! 83: uid_t our_uid;
! 84: int am_receiver = 0; /* Only set to 1 after the receiver/generator fork. */
! 85: int am_generator = 0; /* Only set to 1 after the receiver/generator fork. */
! 86: int local_server = 0;
! 87: int daemon_over_rsh = 0;
! 88: mode_t orig_umask = 0;
! 89: int batch_gen_fd = -1;
! 90:
! 91: /* There's probably never more than at most 2 outstanding child processes,
! 92: * but set it higher, just in case. */
! 93: #define MAXCHILDPROCS 7
! 94:
! 95: #ifdef HAVE_SIGACTION
! 96: # ifdef HAVE_SIGPROCMASK
! 97: # define SIGACTMASK(n,h) SIGACTION(n,h), sigaddset(&sigmask,(n))
! 98: # else
! 99: # define SIGACTMASK(n,h) SIGACTION(n,h)
! 100: # endif
! 101: static struct sigaction sigact;
! 102: #endif
! 103:
! 104: struct pid_status {
! 105: pid_t pid;
! 106: int status;
! 107: } pid_stat_table[MAXCHILDPROCS];
! 108:
! 109: static time_t starttime, endtime;
! 110: static int64 total_read, total_written;
! 111:
! 112: static void show_malloc_stats(void);
! 113:
! 114: /* Works like waitpid(), but if we already harvested the child pid in our
! 115: * remember_children(), we succeed instead of returning an error. */
! 116: pid_t wait_process(pid_t pid, int *status_ptr, int flags)
! 117: {
! 118: pid_t waited_pid;
! 119:
! 120: do {
! 121: waited_pid = waitpid(pid, status_ptr, flags);
! 122: } while (waited_pid == -1 && errno == EINTR);
! 123:
! 124: if (waited_pid == -1 && errno == ECHILD) {
! 125: /* Status of requested child no longer available: check to
! 126: * see if it was processed by remember_children(). */
! 127: int cnt;
! 128: for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
! 129: if (pid == pid_stat_table[cnt].pid) {
! 130: *status_ptr = pid_stat_table[cnt].status;
! 131: pid_stat_table[cnt].pid = 0;
! 132: return pid;
! 133: }
! 134: }
! 135: }
! 136:
! 137: return waited_pid;
! 138: }
! 139:
! 140: /* Wait for a process to exit, calling io_flush while waiting. */
! 141: static void wait_process_with_flush(pid_t pid, int *exit_code_ptr)
! 142: {
! 143: pid_t waited_pid;
! 144: int status;
! 145:
! 146: while ((waited_pid = wait_process(pid, &status, WNOHANG)) == 0) {
! 147: msleep(20);
! 148: io_flush(FULL_FLUSH);
! 149: }
! 150:
! 151: /* TODO: If the child exited on a signal, then log an
! 152: * appropriate error message. Perhaps we should also accept a
! 153: * message describing the purpose of the child. Also indicate
! 154: * this to the caller so that they know something went wrong. */
! 155: if (waited_pid < 0) {
! 156: rsyserr(FERROR, errno, "waitpid");
! 157: *exit_code_ptr = RERR_WAITCHILD;
! 158: } else if (!WIFEXITED(status)) {
! 159: #ifdef WCOREDUMP
! 160: if (WCOREDUMP(status))
! 161: *exit_code_ptr = RERR_CRASHED;
! 162: else
! 163: #endif
! 164: if (WIFSIGNALED(status))
! 165: *exit_code_ptr = RERR_TERMINATED;
! 166: else
! 167: *exit_code_ptr = RERR_WAITCHILD;
! 168: } else
! 169: *exit_code_ptr = WEXITSTATUS(status);
! 170: }
! 171:
! 172: /* This function gets called from all 3 processes. We want the client side
! 173: * to actually output the text, but the sender is the only process that has
! 174: * all the stats we need. So, if we're a client sender, we do the report.
! 175: * If we're a server sender, we write the stats on the supplied fd. If
! 176: * we're the client receiver we read the stats from the supplied fd and do
! 177: * the report. All processes might also generate a set of debug stats, if
! 178: * the verbose level is high enough (this is the only thing that the
! 179: * generator process and the server receiver ever do here). */
! 180: static void handle_stats(int f)
! 181: {
! 182: endtime = time(NULL);
! 183:
! 184: /* Cache two stats because the read/write code can change it. */
! 185: total_read = stats.total_read;
! 186: total_written = stats.total_written;
! 187:
! 188: if (do_stats && verbose > 1) {
! 189: /* These come out from every process */
! 190: show_malloc_stats();
! 191: show_flist_stats();
! 192: }
! 193:
! 194: if (am_generator)
! 195: return;
! 196:
! 197: if (am_daemon) {
! 198: if (f == -1 || !am_sender)
! 199: return;
! 200: }
! 201:
! 202: if (am_server) {
! 203: if (am_sender) {
! 204: write_varlong30(f, total_read, 3);
! 205: write_varlong30(f, total_written, 3);
! 206: write_varlong30(f, stats.total_size, 3);
! 207: if (protocol_version >= 29) {
! 208: write_varlong30(f, stats.flist_buildtime, 3);
! 209: write_varlong30(f, stats.flist_xfertime, 3);
! 210: }
! 211: }
! 212: return;
! 213: }
! 214:
! 215: /* this is the client */
! 216:
! 217: if (f < 0 && !am_sender) /* e.g. when we got an empty file list. */
! 218: ;
! 219: else if (!am_sender) {
! 220: /* Read the first two in opposite order because the meaning of
! 221: * read/write swaps when switching from sender to receiver. */
! 222: total_written = read_varlong30(f, 3);
! 223: total_read = read_varlong30(f, 3);
! 224: stats.total_size = read_varlong30(f, 3);
! 225: if (protocol_version >= 29) {
! 226: stats.flist_buildtime = read_varlong30(f, 3);
! 227: stats.flist_xfertime = read_varlong30(f, 3);
! 228: }
! 229: } else if (write_batch) {
! 230: /* The --read-batch process is going to be a client
! 231: * receiver, so we need to give it the stats. */
! 232: write_varlong30(batch_fd, total_read, 3);
! 233: write_varlong30(batch_fd, total_written, 3);
! 234: write_varlong30(batch_fd, stats.total_size, 3);
! 235: if (protocol_version >= 29) {
! 236: write_varlong30(batch_fd, stats.flist_buildtime, 3);
! 237: write_varlong30(batch_fd, stats.flist_xfertime, 3);
! 238: }
! 239: }
! 240: }
! 241:
! 242: static void output_summary(void)
! 243: {
! 244: if (do_stats) {
! 245: rprintf(FCLIENT, "\n");
! 246: rprintf(FINFO,"Number of files: %d\n", stats.num_files);
! 247: rprintf(FINFO,"Number of files transferred: %d\n",
! 248: stats.num_transferred_files);
! 249: rprintf(FINFO,"Total file size: %s bytes\n",
! 250: human_num(stats.total_size));
! 251: rprintf(FINFO,"Total transferred file size: %s bytes\n",
! 252: human_num(stats.total_transferred_size));
! 253: rprintf(FINFO,"Literal data: %s bytes\n",
! 254: human_num(stats.literal_data));
! 255: rprintf(FINFO,"Matched data: %s bytes\n",
! 256: human_num(stats.matched_data));
! 257: rprintf(FINFO,"File list size: %s\n",
! 258: human_num(stats.flist_size));
! 259: if (stats.flist_buildtime) {
! 260: rprintf(FINFO,
! 261: "File list generation time: %.3f seconds\n",
! 262: (double)stats.flist_buildtime / 1000);
! 263: rprintf(FINFO,
! 264: "File list transfer time: %.3f seconds\n",
! 265: (double)stats.flist_xfertime / 1000);
! 266: }
! 267: rprintf(FINFO,"Total bytes sent: %s\n",
! 268: human_num(total_written));
! 269: rprintf(FINFO,"Total bytes received: %s\n",
! 270: human_num(total_read));
! 271: }
! 272:
! 273: if (verbose || do_stats) {
! 274: rprintf(FCLIENT, "\n");
! 275: rprintf(FINFO,
! 276: "sent %s bytes received %s bytes %s bytes/sec\n",
! 277: human_num(total_written), human_num(total_read),
! 278: human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2));
! 279: rprintf(FINFO, "total size is %s speedup is %.2f%s\n",
! 280: human_num(stats.total_size),
! 281: (double)stats.total_size / (total_written+total_read),
! 282: write_batch < 0 ? " (BATCH ONLY)" : dry_run ? " (DRY RUN)" : "");
! 283: }
! 284:
! 285: fflush(stdout);
! 286: fflush(stderr);
! 287: }
! 288:
! 289:
! 290: /**
! 291: * If our C library can get malloc statistics, then show them to FINFO
! 292: **/
! 293: static void show_malloc_stats(void)
! 294: {
! 295: #ifdef HAVE_MALLINFO
! 296: struct mallinfo mi;
! 297:
! 298: mi = mallinfo();
! 299:
! 300: rprintf(FCLIENT, "\n");
! 301: rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n",
! 302: getpid(), am_server ? "server " : "",
! 303: am_daemon ? "daemon " : "", who_am_i());
! 304: rprintf(FINFO, " arena: %10ld (bytes from sbrk)\n",
! 305: (long)mi.arena);
! 306: rprintf(FINFO, " ordblks: %10ld (chunks not in use)\n",
! 307: (long)mi.ordblks);
! 308: rprintf(FINFO, " smblks: %10ld\n",
! 309: (long)mi.smblks);
! 310: rprintf(FINFO, " hblks: %10ld (chunks from mmap)\n",
! 311: (long)mi.hblks);
! 312: rprintf(FINFO, " hblkhd: %10ld (bytes from mmap)\n",
! 313: (long)mi.hblkhd);
! 314: rprintf(FINFO, " allmem: %10ld (bytes from sbrk + mmap)\n",
! 315: (long)mi.arena + mi.hblkhd);
! 316: rprintf(FINFO, " usmblks: %10ld\n",
! 317: (long)mi.usmblks);
! 318: rprintf(FINFO, " fsmblks: %10ld\n",
! 319: (long)mi.fsmblks);
! 320: rprintf(FINFO, " uordblks: %10ld (bytes used)\n",
! 321: (long)mi.uordblks);
! 322: rprintf(FINFO, " fordblks: %10ld (bytes free)\n",
! 323: (long)mi.fordblks);
! 324: rprintf(FINFO, " keepcost: %10ld (bytes in releasable chunk)\n",
! 325: (long)mi.keepcost);
! 326: #endif /* HAVE_MALLINFO */
! 327: }
! 328:
! 329:
! 330: /* Start the remote shell. cmd may be NULL to use the default. */
! 331: static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, int remote_argc,
! 332: int *f_in_p, int *f_out_p)
! 333: {
! 334: int i, argc = 0;
! 335: char *args[MAX_ARGS];
! 336: pid_t pid;
! 337: int dash_l_set = 0;
! 338:
! 339: if (!read_batch && !local_server) {
! 340: char *t, *f, in_quote = '\0';
! 341: char *rsh_env = getenv(RSYNC_RSH_ENV);
! 342: if (!cmd)
! 343: cmd = rsh_env;
! 344: if (!cmd)
! 345: cmd = RSYNC_RSH;
! 346: cmd = strdup(cmd); /* MEMORY LEAK */
! 347: if (!cmd)
! 348: goto oom;
! 349:
! 350: for (t = f = cmd; *f; f++) {
! 351: if (*f == ' ')
! 352: continue;
! 353: /* Comparison leaves rooms for server_options(). */
! 354: if (argc >= MAX_ARGS - MAX_SERVER_ARGS)
! 355: goto arg_overflow;
! 356: args[argc++] = t;
! 357: while (*f != ' ' || in_quote) {
! 358: if (!*f) {
! 359: if (in_quote) {
! 360: rprintf(FERROR,
! 361: "Missing trailing-%c in remote-shell command.\n",
! 362: in_quote);
! 363: exit_cleanup(RERR_SYNTAX);
! 364: }
! 365: f--;
! 366: break;
! 367: }
! 368: if (*f == '\'' || *f == '"') {
! 369: if (!in_quote) {
! 370: in_quote = *f++;
! 371: continue;
! 372: }
! 373: if (*f == in_quote && *++f != in_quote) {
! 374: in_quote = '\0';
! 375: continue;
! 376: }
! 377: }
! 378: *t++ = *f++;
! 379: }
! 380: *t++ = '\0';
! 381: }
! 382:
! 383: /* check to see if we've already been given '-l user' in
! 384: * the remote-shell command */
! 385: for (i = 0; i < argc-1; i++) {
! 386: if (!strcmp(args[i], "-l") && args[i+1][0] != '-')
! 387: dash_l_set = 1;
! 388: }
! 389:
! 390: #ifdef HAVE_REMSH
! 391: /* remsh (on HPUX) takes the arguments the other way around */
! 392: args[argc++] = machine;
! 393: if (user && !(daemon_over_rsh && dash_l_set)) {
! 394: args[argc++] = "-l";
! 395: args[argc++] = user;
! 396: }
! 397: #else
! 398: if (user && !(daemon_over_rsh && dash_l_set)) {
! 399: args[argc++] = "-l";
! 400: args[argc++] = user;
! 401: }
! 402: args[argc++] = machine;
! 403: #endif
! 404:
! 405: args[argc++] = rsync_path;
! 406:
! 407: if (blocking_io < 0) {
! 408: char *cp;
! 409: if ((cp = strrchr(cmd, '/')) != NULL)
! 410: cp++;
! 411: else
! 412: cp = cmd;
! 413: if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0)
! 414: blocking_io = 1;
! 415: }
! 416:
! 417: server_options(args,&argc);
! 418:
! 419: if (argc >= MAX_ARGS - 2)
! 420: goto arg_overflow;
! 421: }
! 422:
! 423: args[argc++] = ".";
! 424:
! 425: if (!daemon_over_rsh) {
! 426: while (remote_argc > 0) {
! 427: if (argc >= MAX_ARGS - 1) {
! 428: arg_overflow:
! 429: rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n");
! 430: exit_cleanup(RERR_SYNTAX);
! 431: }
! 432: if (**remote_argv == '-') {
! 433: if (asprintf(args + argc++, "./%s", *remote_argv++) < 0)
! 434: out_of_memory("do_cmd");
! 435: } else
! 436: args[argc++] = *remote_argv++;
! 437: remote_argc--;
! 438: }
! 439: }
! 440:
! 441: args[argc] = NULL;
! 442:
! 443: if (verbose > 3) {
! 444: for (i = 0; i < argc; i++)
! 445: rprintf(FCLIENT, "cmd[%d]=%s ", i, args[i]);
! 446: rprintf(FCLIENT, "\n");
! 447: }
! 448:
! 449: if (read_batch) {
! 450: int from_gen_pipe[2];
! 451: set_allow_inc_recurse();
! 452: if (fd_pair(from_gen_pipe) < 0) {
! 453: rsyserr(FERROR, errno, "pipe");
! 454: exit_cleanup(RERR_IPC);
! 455: }
! 456: batch_gen_fd = from_gen_pipe[0];
! 457: *f_out_p = from_gen_pipe[1];
! 458: *f_in_p = batch_fd;
! 459: pid = (pid_t)-1; /* no child pid */
! 460: #ifdef ICONV_CONST
! 461: setup_iconv();
! 462: #endif
! 463: } else if (local_server) {
! 464: /* If the user didn't request --[no-]whole-file, force
! 465: * it on, but only if we're not batch processing. */
! 466: if (whole_file < 0 && !write_batch)
! 467: whole_file = 1;
! 468: set_allow_inc_recurse();
! 469: pid = local_child(argc, args, f_in_p, f_out_p, child_main);
! 470: #ifdef ICONV_CONST
! 471: setup_iconv();
! 472: #endif
! 473: } else {
! 474: pid = piped_child(args, f_in_p, f_out_p);
! 475: #ifdef ICONV_CONST
! 476: setup_iconv();
! 477: #endif
! 478: if (protect_args && !daemon_over_rsh)
! 479: send_protected_args(*f_out_p, args);
! 480: }
! 481:
! 482: return pid;
! 483:
! 484: oom:
! 485: out_of_memory("do_cmd");
! 486: return 0; /* not reached */
! 487: }
! 488:
! 489: /* The receiving side operates in one of two modes:
! 490: *
! 491: * 1. it receives any number of files into a destination directory,
! 492: * placing them according to their names in the file-list.
! 493: *
! 494: * 2. it receives a single file and saves it using the name in the
! 495: * destination path instead of its file-list name. This requires a
! 496: * "local name" for writing out the destination file.
! 497: *
! 498: * So, our task is to figure out what mode/local-name we need.
! 499: * For mode 1, we change into the destination directory and return NULL.
! 500: * For mode 2, we change into the directory containing the destination
! 501: * file (if we aren't already there) and return the local-name. */
! 502: static char *get_local_name(struct file_list *flist, char *dest_path)
! 503: {
! 504: STRUCT_STAT st;
! 505: int statret;
! 506: char *cp;
! 507:
! 508: if (verbose > 2) {
! 509: rprintf(FINFO, "get_local_name count=%d %s\n",
! 510: file_total, NS(dest_path));
! 511: }
! 512:
! 513: if (!dest_path || list_only)
! 514: return NULL;
! 515:
! 516: /* Treat an empty string as a copy into the current directory. */
! 517: if (!*dest_path)
! 518: dest_path = ".";
! 519:
! 520: if (daemon_filter_list.head) {
! 521: char *slash = strrchr(dest_path, '/');
! 522: if (slash && (slash[1] == '\0' || (slash[1] == '.' && slash[2] == '\0')))
! 523: *slash = '\0';
! 524: else
! 525: slash = NULL;
! 526: if ((*dest_path != '.' || dest_path[1] != '\0')
! 527: && (check_filter(&daemon_filter_list, FLOG, dest_path, 0) < 0
! 528: || check_filter(&daemon_filter_list, FLOG, dest_path, 1) < 0)) {
! 529: rprintf(FERROR, "ERROR: daemon has excluded destination \"%s\"\n",
! 530: dest_path);
! 531: exit_cleanup(RERR_FILESELECT);
! 532: }
! 533: if (slash)
! 534: *slash = '/';
! 535: }
! 536:
! 537: /* See what currently exists at the destination. */
! 538: if ((statret = do_stat(dest_path, &st)) == 0) {
! 539: /* If the destination is a dir, enter it and use mode 1. */
! 540: if (S_ISDIR(st.st_mode)) {
! 541: if (!change_dir(dest_path, CD_NORMAL)) {
! 542: rsyserr(FERROR, errno, "change_dir#1 %s failed",
! 543: full_fname(dest_path));
! 544: exit_cleanup(RERR_FILESELECT);
! 545: }
! 546: filesystem_dev = st.st_dev; /* ensures --force works right w/-x */
! 547: return NULL;
! 548: }
! 549: if (file_total > 1) {
! 550: rprintf(FERROR,
! 551: "ERROR: destination must be a directory when"
! 552: " copying more than 1 file\n");
! 553: exit_cleanup(RERR_FILESELECT);
! 554: }
! 555: if (file_total == 1 && S_ISDIR(flist->files[0]->mode)) {
! 556: rprintf(FERROR,
! 557: "ERROR: cannot overwrite non-directory"
! 558: " with a directory\n");
! 559: exit_cleanup(RERR_FILESELECT);
! 560: }
! 561: } else if (errno != ENOENT) {
! 562: /* If we don't know what's at the destination, fail. */
! 563: rsyserr(FERROR, errno, "ERROR: cannot stat destination %s",
! 564: full_fname(dest_path));
! 565: exit_cleanup(RERR_FILESELECT);
! 566: }
! 567:
! 568: cp = strrchr(dest_path, '/');
! 569:
! 570: /* If we need a destination directory because the transfer is not
! 571: * of a single non-directory or the user has requested one via a
! 572: * destination path ending in a slash, create one and use mode 1. */
! 573: if (file_total > 1 || (cp && !cp[1])) {
! 574: /* Lop off the final slash (if any). */
! 575: if (cp && !cp[1])
! 576: *cp = '\0';
! 577:
! 578: if (statret == 0) {
! 579: rprintf(FERROR,
! 580: "ERROR: destination path is not a directory\n");
! 581: exit_cleanup(RERR_SYNTAX);
! 582: }
! 583:
! 584: if (mkdir_defmode(dest_path) != 0) {
! 585: rsyserr(FERROR, errno, "mkdir %s failed",
! 586: full_fname(dest_path));
! 587: exit_cleanup(RERR_FILEIO);
! 588: }
! 589:
! 590: if (flist->high >= flist->low
! 591: && strcmp(flist->files[flist->low]->basename, ".") == 0)
! 592: flist->files[0]->flags |= FLAG_DIR_CREATED;
! 593:
! 594: if (verbose)
! 595: rprintf(FINFO, "created directory %s\n", dest_path);
! 596:
! 597: if (dry_run) {
! 598: /* Indicate that dest dir doesn't really exist. */
! 599: dry_run++;
! 600: }
! 601:
! 602: if (!change_dir(dest_path, dry_run > 1 ? CD_SKIP_CHDIR : CD_NORMAL)) {
! 603: rsyserr(FERROR, errno, "change_dir#2 %s failed",
! 604: full_fname(dest_path));
! 605: exit_cleanup(RERR_FILESELECT);
! 606: }
! 607:
! 608: return NULL;
! 609: }
! 610:
! 611: /* Otherwise, we are writing a single file, possibly on top of an
! 612: * existing non-directory. Change to the item's parent directory
! 613: * (if it has a path component), return the basename of the
! 614: * destination file as the local name, and use mode 2. */
! 615: if (!cp)
! 616: return dest_path;
! 617:
! 618: if (cp == dest_path)
! 619: dest_path = "/";
! 620:
! 621: *cp = '\0';
! 622: if (!change_dir(dest_path, CD_NORMAL)) {
! 623: rsyserr(FERROR, errno, "change_dir#3 %s failed",
! 624: full_fname(dest_path));
! 625: exit_cleanup(RERR_FILESELECT);
! 626: }
! 627: *cp = '/';
! 628:
! 629: return cp + 1;
! 630: }
! 631:
! 632: /* This function checks on our alternate-basis directories. If we're in
! 633: * dry-run mode and the destination dir does not yet exist, we'll try to
! 634: * tweak any dest-relative paths to make them work for a dry-run (the
! 635: * destination dir must be in curr_dir[] when this function is called).
! 636: * We also warn about any arg that is non-existent or not a directory. */
! 637: static void check_alt_basis_dirs(void)
! 638: {
! 639: STRUCT_STAT st;
! 640: char **dir_p, *slash = strrchr(curr_dir, '/');
! 641:
! 642: for (dir_p = basis_dir; *dir_p; dir_p++) {
! 643: if (dry_run > 1 && **dir_p != '/') {
! 644: int len = curr_dir_len + 1 + strlen(*dir_p) + 1;
! 645: char *new = new_array(char, len);
! 646: if (!new)
! 647: out_of_memory("check_alt_basis_dirs");
! 648: if (slash && strncmp(*dir_p, "../", 3) == 0) {
! 649: /* We want to remove only one leading "../" prefix for
! 650: * the directory we couldn't create in dry-run mode:
! 651: * this ensures that any other ".." references get
! 652: * evaluated the same as they would for a live copy. */
! 653: *slash = '\0';
! 654: pathjoin(new, len, curr_dir, *dir_p + 3);
! 655: *slash = '/';
! 656: } else
! 657: pathjoin(new, len, curr_dir, *dir_p);
! 658: *dir_p = new;
! 659: }
! 660: if (do_stat(*dir_p, &st) < 0) {
! 661: rprintf(FWARNING, "%s arg does not exist: %s\n",
! 662: dest_option, *dir_p);
! 663: } else if (!S_ISDIR(st.st_mode)) {
! 664: rprintf(FWARNING, "%s arg is not a dir: %s\n",
! 665: dest_option, *dir_p);
! 666: }
! 667: }
! 668: }
! 669:
! 670: /* This is only called by the sender. */
! 671: static void read_final_goodbye(int f_in)
! 672: {
! 673: int i, iflags, xlen;
! 674: uchar fnamecmp_type;
! 675: char xname[MAXPATHLEN];
! 676:
! 677: if (protocol_version < 29)
! 678: i = read_int(f_in);
! 679: else {
! 680: i = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
! 681: xname, &xlen);
! 682: }
! 683:
! 684: if (i != NDX_DONE) {
! 685: rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n",
! 686: i, who_am_i());
! 687: exit_cleanup(RERR_PROTOCOL);
! 688: }
! 689: }
! 690:
! 691: static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
! 692: {
! 693: struct file_list *flist;
! 694: char *dir = argv[0];
! 695:
! 696: if (verbose > 2) {
! 697: rprintf(FINFO, "server_sender starting pid=%ld\n",
! 698: (long)getpid());
! 699: }
! 700:
! 701: if (am_daemon && lp_write_only(module_id)) {
! 702: rprintf(FERROR, "ERROR: module is write only\n");
! 703: exit_cleanup(RERR_SYNTAX);
! 704: return;
! 705: }
! 706: if (am_daemon && lp_read_only(module_id) && remove_source_files) {
! 707: rprintf(FERROR,
! 708: "ERROR: --remove-%s-files cannot be used with a read-only module\n",
! 709: remove_source_files == 1 ? "source" : "sent");
! 710: exit_cleanup(RERR_SYNTAX);
! 711: return;
! 712: }
! 713:
! 714: if (!relative_paths) {
! 715: if (!change_dir(dir, CD_NORMAL)) {
! 716: rsyserr(FERROR, errno, "change_dir#3 %s failed",
! 717: full_fname(dir));
! 718: exit_cleanup(RERR_FILESELECT);
! 719: }
! 720: }
! 721: argc--;
! 722: argv++;
! 723:
! 724: if (argc == 0 && (recurse || xfer_dirs || list_only)) {
! 725: argc = 1;
! 726: argv--;
! 727: argv[0] = ".";
! 728: }
! 729:
! 730: flist = send_file_list(f_out,argc,argv);
! 731: if (!flist || flist->used == 0)
! 732: exit_cleanup(0);
! 733:
! 734: io_start_buffering_in(f_in);
! 735:
! 736: send_files(f_in, f_out);
! 737: io_flush(FULL_FLUSH);
! 738: handle_stats(f_out);
! 739: if (protocol_version >= 24)
! 740: read_final_goodbye(f_in);
! 741: io_flush(FULL_FLUSH);
! 742: exit_cleanup(0);
! 743: }
! 744:
! 745:
! 746: static int do_recv(int f_in, int f_out, char *local_name)
! 747: {
! 748: int pid;
! 749: int exit_code = 0;
! 750: int error_pipe[2];
! 751:
! 752: /* The receiving side mustn't obey this, or an existing symlink that
! 753: * points to an identical file won't be replaced by the referent. */
! 754: copy_links = copy_dirlinks = copy_unsafe_links = 0;
! 755:
! 756: #ifdef SUPPORT_HARD_LINKS
! 757: if (preserve_hard_links && !inc_recurse)
! 758: match_hard_links(first_flist);
! 759: #endif
! 760:
! 761: if (fd_pair(error_pipe) < 0) {
! 762: rsyserr(FERROR, errno, "pipe failed in do_recv");
! 763: exit_cleanup(RERR_IPC);
! 764: }
! 765:
! 766: io_flush(NORMAL_FLUSH);
! 767:
! 768: if ((pid = do_fork()) == -1) {
! 769: rsyserr(FERROR, errno, "fork failed in do_recv");
! 770: exit_cleanup(RERR_IPC);
! 771: }
! 772:
! 773: if (pid == 0) {
! 774: am_receiver = 1;
! 775:
! 776: close(error_pipe[0]);
! 777: if (f_in != f_out)
! 778: close(f_out);
! 779:
! 780: /* we can't let two processes write to the socket at one time */
! 781: io_end_multiplex_out();
! 782:
! 783: /* set place to send errors */
! 784: set_msg_fd_out(error_pipe[1]);
! 785: io_start_buffering_out(error_pipe[1]);
! 786:
! 787: recv_files(f_in, local_name);
! 788: io_flush(FULL_FLUSH);
! 789: handle_stats(f_in);
! 790:
! 791: send_msg(MSG_DONE, "", 1, 0);
! 792: write_varlong(error_pipe[1], stats.total_read, 3);
! 793: io_flush(FULL_FLUSH);
! 794:
! 795: /* Handle any keep-alive packets from the post-processing work
! 796: * that the generator does. */
! 797: if (protocol_version >= 29) {
! 798: int iflags, xlen;
! 799: uchar fnamecmp_type;
! 800: char xname[MAXPATHLEN];
! 801:
! 802: kluge_around_eof = -1;
! 803:
! 804: /* This should only get stopped via a USR2 signal. */
! 805: read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
! 806: xname, &xlen);
! 807:
! 808: rprintf(FERROR, "Invalid packet at end of run [%s]\n",
! 809: who_am_i());
! 810: exit_cleanup(RERR_PROTOCOL);
! 811: }
! 812:
! 813: /* Finally, we go to sleep until our parent kills us with a
! 814: * USR2 signal. We sleep for a short time, as on some OSes
! 815: * a signal won't interrupt a sleep! */
! 816: while (1)
! 817: msleep(20);
! 818: }
! 819:
! 820: am_generator = 1;
! 821:
! 822: io_end_multiplex_in();
! 823: if (write_batch && !am_server)
! 824: stop_write_batch();
! 825:
! 826: close(error_pipe[1]);
! 827: if (f_in != f_out)
! 828: close(f_in);
! 829:
! 830: io_start_buffering_out(f_out);
! 831:
! 832: set_msg_fd_in(error_pipe[0]);
! 833: io_start_buffering_in(error_pipe[0]);
! 834:
! 835: #ifdef SUPPORT_HARD_LINKS
! 836: if (preserve_hard_links && inc_recurse) {
! 837: struct file_list *flist;
! 838: for (flist = first_flist; flist; flist = flist->next)
! 839: match_hard_links(flist);
! 840: }
! 841: #endif
! 842:
! 843: generate_files(f_out, local_name);
! 844:
! 845: handle_stats(-1);
! 846: io_flush(FULL_FLUSH);
! 847: if (protocol_version >= 24) {
! 848: /* send a final goodbye message */
! 849: write_ndx(f_out, NDX_DONE);
! 850: }
! 851: io_flush(FULL_FLUSH);
! 852:
! 853: set_msg_fd_in(-1);
! 854: kill(pid, SIGUSR2);
! 855: wait_process_with_flush(pid, &exit_code);
! 856: return exit_code;
! 857: }
! 858:
! 859: static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
! 860: {
! 861: int exit_code;
! 862: struct file_list *flist;
! 863: char *local_name = NULL;
! 864: int save_verbose = verbose;
! 865:
! 866: if (filesfrom_fd >= 0) {
! 867: /* We can't mix messages with files-from data on the socket,
! 868: * so temporarily turn off verbose messages. */
! 869: verbose = 0;
! 870: }
! 871:
! 872: if (verbose > 2) {
! 873: rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
! 874: argc, (long)getpid());
! 875: }
! 876:
! 877: if (am_daemon && lp_read_only(module_id)) {
! 878: rprintf(FERROR,"ERROR: module is read only\n");
! 879: exit_cleanup(RERR_SYNTAX);
! 880: return;
! 881: }
! 882:
! 883: if (argc > 0) {
! 884: char *dir = argv[0];
! 885: argc--;
! 886: argv++;
! 887: if (!am_daemon && !change_dir(dir, CD_NORMAL)) {
! 888: rsyserr(FERROR, errno, "change_dir#4 %s failed",
! 889: full_fname(dir));
! 890: exit_cleanup(RERR_FILESELECT);
! 891: }
! 892: }
! 893:
! 894: if (protocol_version >= 30)
! 895: io_start_multiplex_in();
! 896: else
! 897: io_start_buffering_in(f_in);
! 898: recv_filter_list(f_in);
! 899:
! 900: if (filesfrom_fd >= 0) {
! 901: /* We need to send the files-from names to the sender at the
! 902: * same time that we receive the file-list from them, so we
! 903: * need the IO routines to automatically write out the names
! 904: * onto our f_out socket as we read the file-list. This
! 905: * avoids both deadlock and extra delays/buffers. */
! 906: io_set_filesfrom_fds(filesfrom_fd, f_out);
! 907: filesfrom_fd = -1;
! 908: }
! 909:
! 910: flist = recv_file_list(f_in);
! 911: if (!flist) {
! 912: rprintf(FERROR,"server_recv: recv_file_list error\n");
! 913: exit_cleanup(RERR_FILESELECT);
! 914: }
! 915: if (inc_recurse && file_total == 1)
! 916: recv_additional_file_list(f_in);
! 917: verbose = save_verbose;
! 918:
! 919: if (argc > 0)
! 920: local_name = get_local_name(flist,argv[0]);
! 921:
! 922: /* Now that we know what our destination directory turned out to be,
! 923: * we can sanitize the --link-/copy-/compare-dest args correctly. */
! 924: if (sanitize_paths) {
! 925: char **dir_p;
! 926: for (dir_p = basis_dir; *dir_p; dir_p++)
! 927: *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);
! 928: if (partial_dir)
! 929: partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);
! 930: }
! 931: check_alt_basis_dirs();
! 932:
! 933: if (daemon_filter_list.head) {
! 934: char **dir_p;
! 935: struct filter_list_struct *elp = &daemon_filter_list;
! 936:
! 937: for (dir_p = basis_dir; *dir_p; dir_p++) {
! 938: char *dir = *dir_p;
! 939: if (*dir == '/')
! 940: dir += module_dirlen;
! 941: if (check_filter(elp, FLOG, dir, 1) < 0)
! 942: goto options_rejected;
! 943: }
! 944: if (partial_dir && *partial_dir == '/'
! 945: && check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {
! 946: options_rejected:
! 947: rprintf(FERROR,
! 948: "Your options have been rejected by the server.\n");
! 949: exit_cleanup(RERR_SYNTAX);
! 950: }
! 951: }
! 952:
! 953: exit_code = do_recv(f_in, f_out, local_name);
! 954: exit_cleanup(exit_code);
! 955: }
! 956:
! 957:
! 958: int child_main(int argc, char *argv[])
! 959: {
! 960: start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
! 961: return 0;
! 962: }
! 963:
! 964:
! 965: void start_server(int f_in, int f_out, int argc, char *argv[])
! 966: {
! 967: set_nonblocking(f_in);
! 968: set_nonblocking(f_out);
! 969:
! 970: io_set_sock_fds(f_in, f_out);
! 971: setup_protocol(f_out, f_in);
! 972:
! 973: if (protocol_version >= 23)
! 974: io_start_multiplex_out();
! 975:
! 976: if (am_sender) {
! 977: keep_dirlinks = 0; /* Must be disabled on the sender. */
! 978: if (need_messages_from_generator)
! 979: io_start_multiplex_in();
! 980: recv_filter_list(f_in);
! 981: do_server_sender(f_in, f_out, argc, argv);
! 982: } else
! 983: do_server_recv(f_in, f_out, argc, argv);
! 984: exit_cleanup(0);
! 985: }
! 986:
! 987:
! 988: /*
! 989: * This is called once the connection has been negotiated. It is used
! 990: * for rsyncd, remote-shell, and local connections.
! 991: */
! 992: int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
! 993: {
! 994: struct file_list *flist = NULL;
! 995: int exit_code = 0, exit_code2 = 0;
! 996: char *local_name = NULL;
! 997:
! 998: cleanup_child_pid = pid;
! 999: if (!read_batch) {
! 1000: set_nonblocking(f_in);
! 1001: set_nonblocking(f_out);
! 1002: }
! 1003:
! 1004: io_set_sock_fds(f_in, f_out);
! 1005: setup_protocol(f_out,f_in);
! 1006:
! 1007: /* We set our stderr file handle to blocking because ssh might have
! 1008: * set it to non-blocking. This can be particularly troublesome if
! 1009: * stderr is a clone of stdout, because ssh would have set our stdout
! 1010: * to non-blocking at the same time (which can easily cause us to lose
! 1011: * output from our print statements). This kluge shouldn't cause ssh
! 1012: * any problems for how we use it. Note also that we delayed setting
! 1013: * this until after the above protocol setup so that we know for sure
! 1014: * that ssh is done twiddling its file descriptors. */
! 1015: set_blocking(STDERR_FILENO);
! 1016:
! 1017: if (am_sender) {
! 1018: keep_dirlinks = 0; /* Must be disabled on the sender. */
! 1019: if (protocol_version >= 30)
! 1020: io_start_multiplex_out();
! 1021: else
! 1022: io_start_buffering_out(f_out);
! 1023: if (!filesfrom_host)
! 1024: set_msg_fd_in(f_in);
! 1025: send_filter_list(f_out);
! 1026: if (filesfrom_host)
! 1027: filesfrom_fd = f_in;
! 1028:
! 1029: if (write_batch && !am_server)
! 1030: start_write_batch(f_out);
! 1031: flist = send_file_list(f_out, argc, argv);
! 1032: if (verbose > 3)
! 1033: rprintf(FINFO,"file list sent\n");
! 1034:
! 1035: if (protocol_version >= 23)
! 1036: io_start_multiplex_in();
! 1037:
! 1038: io_flush(NORMAL_FLUSH);
! 1039: send_files(f_in, f_out);
! 1040: io_flush(FULL_FLUSH);
! 1041: handle_stats(-1);
! 1042: if (protocol_version >= 24)
! 1043: read_final_goodbye(f_in);
! 1044: if (pid != -1) {
! 1045: if (verbose > 3)
! 1046: rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
! 1047: io_flush(FULL_FLUSH);
! 1048: wait_process_with_flush(pid, &exit_code);
! 1049: }
! 1050: output_summary();
! 1051: io_flush(FULL_FLUSH);
! 1052: exit_cleanup(exit_code);
! 1053: }
! 1054:
! 1055: if (!read_batch) {
! 1056: if (protocol_version >= 23)
! 1057: io_start_multiplex_in();
! 1058: if (need_messages_from_generator)
! 1059: io_start_multiplex_out();
! 1060: }
! 1061:
! 1062: send_filter_list(read_batch ? -1 : f_out);
! 1063:
! 1064: if (filesfrom_fd >= 0) {
! 1065: io_set_filesfrom_fds(filesfrom_fd, f_out);
! 1066: filesfrom_fd = -1;
! 1067: }
! 1068:
! 1069: if (write_batch && !am_server)
! 1070: start_write_batch(f_in);
! 1071: flist = recv_file_list(f_in);
! 1072: if (inc_recurse && file_total == 1)
! 1073: recv_additional_file_list(f_in);
! 1074:
! 1075: if (flist && flist->used > 0) {
! 1076: local_name = get_local_name(flist, argv[0]);
! 1077:
! 1078: check_alt_basis_dirs();
! 1079:
! 1080: exit_code2 = do_recv(f_in, f_out, local_name);
! 1081: } else {
! 1082: handle_stats(-1);
! 1083: output_summary();
! 1084: }
! 1085:
! 1086: if (pid != -1) {
! 1087: if (verbose > 3)
! 1088: rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
! 1089: io_flush(FULL_FLUSH);
! 1090: wait_process_with_flush(pid, &exit_code);
! 1091: }
! 1092:
! 1093: return MAX(exit_code, exit_code2);
! 1094: }
! 1095:
! 1096: static int copy_argv(char *argv[])
! 1097: {
! 1098: int i;
! 1099:
! 1100: for (i = 0; argv[i]; i++) {
! 1101: if (!(argv[i] = strdup(argv[i]))) {
! 1102: rprintf (FERROR, "out of memory at %s(%d)\n",
! 1103: __FILE__, __LINE__);
! 1104: return RERR_MALLOC;
! 1105: }
! 1106: }
! 1107:
! 1108: return 0;
! 1109: }
! 1110:
! 1111:
! 1112: /**
! 1113: * Start a client for either type of remote connection. Work out
! 1114: * whether the arguments request a remote shell or rsyncd connection,
! 1115: * and call the appropriate connection function, then run_client.
! 1116: *
! 1117: * Calls either start_socket_client (for sockets) or do_cmd and
! 1118: * client_run (for ssh).
! 1119: **/
! 1120: static int start_client(int argc, char *argv[])
! 1121: {
! 1122: char *p, *shell_machine = NULL, *shell_user = NULL;
! 1123: char **remote_argv;
! 1124: int remote_argc;
! 1125: int f_in, f_out;
! 1126: int ret;
! 1127: pid_t pid;
! 1128:
! 1129: /* Don't clobber argv[] so that ps(1) can still show the right
! 1130: * command line. */
! 1131: if ((ret = copy_argv(argv)) != 0)
! 1132: return ret;
! 1133:
! 1134: if (!read_batch) { /* for read_batch, NO source is specified */
! 1135: char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port);
! 1136: if (path) { /* source is remote */
! 1137: char *dummy_host;
! 1138: int dummy_port = 0;
! 1139: *argv = path;
! 1140: remote_argv = argv;
! 1141: remote_argc = argc;
! 1142: argv += argc - 1;
! 1143: if (argc == 1 || **argv == ':')
! 1144: argc = 0; /* no dest arg */
! 1145: else if (check_for_hostspec(*argv, &dummy_host, &dummy_port)) {
! 1146: rprintf(FERROR,
! 1147: "The source and destination cannot both be remote.\n");
! 1148: exit_cleanup(RERR_SYNTAX);
! 1149: } else {
! 1150: remote_argc--; /* don't count dest */
! 1151: argc = 1;
! 1152: }
! 1153: if (filesfrom_host && *filesfrom_host
! 1154: && strcmp(filesfrom_host, shell_machine) != 0) {
! 1155: rprintf(FERROR,
! 1156: "--files-from hostname is not the same as the transfer hostname\n");
! 1157: exit_cleanup(RERR_SYNTAX);
! 1158: }
! 1159: am_sender = 0;
! 1160: if (rsync_port)
! 1161: daemon_over_rsh = shell_cmd ? 1 : -1;
! 1162: } else { /* source is local, check dest arg */
! 1163: am_sender = 1;
! 1164:
! 1165: if (argc > 1) {
! 1166: p = argv[--argc];
! 1167: remote_argv = argv + argc;
! 1168: } else {
! 1169: static char *dotarg[1] = { "." };
! 1170: p = dotarg[0];
! 1171: remote_argv = dotarg;
! 1172: }
! 1173: remote_argc = 1;
! 1174:
! 1175: path = check_for_hostspec(p, &shell_machine, &rsync_port);
! 1176: if (path && filesfrom_host && *filesfrom_host
! 1177: && strcmp(filesfrom_host, shell_machine) != 0) {
! 1178: rprintf(FERROR,
! 1179: "--files-from hostname is not the same as the transfer hostname\n");
! 1180: exit_cleanup(RERR_SYNTAX);
! 1181: }
! 1182: if (!path) { /* no hostspec found, so src & dest are local */
! 1183: local_server = 1;
! 1184: if (filesfrom_host) {
! 1185: rprintf(FERROR,
! 1186: "--files-from cannot be remote when the transfer is local\n");
! 1187: exit_cleanup(RERR_SYNTAX);
! 1188: }
! 1189: shell_machine = NULL;
! 1190: } else { /* hostspec was found, so dest is remote */
! 1191: argv[argc] = path;
! 1192: if (rsync_port)
! 1193: daemon_over_rsh = shell_cmd ? 1 : -1;
! 1194: }
! 1195: }
! 1196: } else { /* read_batch */
! 1197: local_server = 1;
! 1198: if (check_for_hostspec(argv[argc-1], &shell_machine, &rsync_port)) {
! 1199: rprintf(FERROR, "remote destination is not allowed with --read-batch\n");
! 1200: exit_cleanup(RERR_SYNTAX);
! 1201: }
! 1202: remote_argv = argv += argc - 1;
! 1203: remote_argc = argc = 1;
! 1204: }
! 1205:
! 1206: if (am_sender) {
! 1207: char *dummy_host;
! 1208: int dummy_port = rsync_port;
! 1209: int i;
! 1210: /* For local source, extra source args must not have hostspec. */
! 1211: for (i = 1; i < argc; i++) {
! 1212: if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) {
! 1213: rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]);
! 1214: exit_cleanup(RERR_SYNTAX);
! 1215: }
! 1216: }
! 1217: } else {
! 1218: char *dummy_host;
! 1219: int dummy_port = rsync_port;
! 1220: int i;
! 1221: /* For remote source, any extra source args must have either
! 1222: * the same hostname or an empty hostname. */
! 1223: for (i = 1; i < remote_argc; i++) {
! 1224: char *arg = check_for_hostspec(remote_argv[i], &dummy_host, &dummy_port);
! 1225: if (!arg) {
! 1226: rprintf(FERROR, "Unexpected local arg: %s\n", remote_argv[i]);
! 1227: rprintf(FERROR, "If arg is a remote file/dir, prefix it with a colon (:).\n");
! 1228: exit_cleanup(RERR_SYNTAX);
! 1229: }
! 1230: if (*dummy_host && strcmp(dummy_host, shell_machine) != 0) {
! 1231: rprintf(FERROR, "All source args must come from the same machine.\n");
! 1232: exit_cleanup(RERR_SYNTAX);
! 1233: }
! 1234: if (rsync_port != dummy_port) {
! 1235: if (!rsync_port || !dummy_port)
! 1236: rprintf(FERROR, "All source args must use the same hostspec format.\n");
! 1237: else
! 1238: rprintf(FERROR, "All source args must use the same port number.\n");
! 1239: exit_cleanup(RERR_SYNTAX);
! 1240: }
! 1241: remote_argv[i] = arg;
! 1242: }
! 1243: }
! 1244:
! 1245: if (daemon_over_rsh < 0)
! 1246: return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv);
! 1247:
! 1248: if (password_file && !daemon_over_rsh) {
! 1249: rprintf(FERROR, "The --password-file option may only be "
! 1250: "used when accessing an rsync daemon.\n");
! 1251: exit_cleanup(RERR_SYNTAX);
! 1252: }
! 1253:
! 1254: if (connect_timeout) {
! 1255: rprintf(FERROR, "The --contimeout option may only be "
! 1256: "used when connecting to an rsync daemon.\n");
! 1257: exit_cleanup(RERR_SYNTAX);
! 1258: }
! 1259:
! 1260: if (shell_machine) {
! 1261: p = strrchr(shell_machine,'@');
! 1262: if (p) {
! 1263: *p = 0;
! 1264: shell_user = shell_machine;
! 1265: shell_machine = p+1;
! 1266: }
! 1267: }
! 1268:
! 1269: if (verbose > 3) {
! 1270: rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
! 1271: NS(shell_cmd), NS(shell_machine), NS(shell_user),
! 1272: remote_argv ? NS(remote_argv[0]) : "");
! 1273: }
! 1274:
! 1275: pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
! 1276: &f_in, &f_out);
! 1277:
! 1278: /* if we're running an rsync server on the remote host over a
! 1279: * remote shell command, we need to do the RSYNCD protocol first */
! 1280: if (daemon_over_rsh) {
! 1281: int tmpret;
! 1282: tmpret = start_inband_exchange(f_in, f_out, shell_user, remote_argc, remote_argv);
! 1283: if (tmpret < 0)
! 1284: return tmpret;
! 1285: }
! 1286:
! 1287: ret = client_run(f_in, f_out, pid, argc, argv);
! 1288:
! 1289: fflush(stdout);
! 1290: fflush(stderr);
! 1291:
! 1292: return ret;
! 1293: }
! 1294:
! 1295:
! 1296: static RETSIGTYPE sigusr1_handler(UNUSED(int val))
! 1297: {
! 1298: exit_cleanup(RERR_SIGNAL1);
! 1299: }
! 1300:
! 1301: static RETSIGTYPE sigusr2_handler(UNUSED(int val))
! 1302: {
! 1303: if (!am_server)
! 1304: output_summary();
! 1305: close_all();
! 1306: if (got_xfer_error)
! 1307: _exit(RERR_PARTIAL);
! 1308: _exit(0);
! 1309: }
! 1310:
! 1311: RETSIGTYPE remember_children(UNUSED(int val))
! 1312: {
! 1313: #ifdef WNOHANG
! 1314: int cnt, status;
! 1315: pid_t pid;
! 1316: /* An empty waitpid() loop was put here by Tridge and we could never
! 1317: * get him to explain why he put it in, so rather than taking it
! 1318: * out we're instead saving the child exit statuses for later use.
! 1319: * The waitpid() loop presumably eliminates all possibility of leaving
! 1320: * zombie children, maybe that's why he did it. */
! 1321: while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
! 1322: /* save the child's exit status */
! 1323: for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) {
! 1324: if (pid_stat_table[cnt].pid == 0) {
! 1325: pid_stat_table[cnt].pid = pid;
! 1326: pid_stat_table[cnt].status = status;
! 1327: break;
! 1328: }
! 1329: }
! 1330: }
! 1331: #endif
! 1332: #ifndef HAVE_SIGACTION
! 1333: signal(SIGCHLD, remember_children);
! 1334: #endif
! 1335: }
! 1336:
! 1337:
! 1338: /**
! 1339: * This routine catches signals and tries to send them to gdb.
! 1340: *
! 1341: * Because it's called from inside a signal handler it ought not to
! 1342: * use too many library routines.
! 1343: *
! 1344: * @todo Perhaps use "screen -X" instead/as well, to help people
! 1345: * debugging without easy access to X. Perhaps use an environment
! 1346: * variable, or just call a script?
! 1347: *
! 1348: * @todo The /proc/ magic probably only works on Linux (and
! 1349: * Solaris?) Can we be more portable?
! 1350: **/
! 1351: #ifdef MAINTAINER_MODE
! 1352: const char *get_panic_action(void)
! 1353: {
! 1354: const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION");
! 1355:
! 1356: if (cmd_fmt)
! 1357: return cmd_fmt;
! 1358: else
! 1359: return "xterm -display :0 -T Panic -n Panic "
! 1360: "-e gdb /proc/%d/exe %d";
! 1361: }
! 1362:
! 1363:
! 1364: /**
! 1365: * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION.
! 1366: *
! 1367: * This signal handler is only installed if we were configured with
! 1368: * --enable-maintainer-mode. Perhaps it should always be on and we
! 1369: * should just look at the environment variable, but I'm a bit leery
! 1370: * of a signal sending us into a busy loop.
! 1371: **/
! 1372: static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig))
! 1373: {
! 1374: char cmd_buf[300];
! 1375: int ret;
! 1376:
! 1377: snprintf(cmd_buf, sizeof cmd_buf, get_panic_action(),
! 1378: getpid(), getpid());
! 1379:
! 1380: /* Unless we failed to execute gdb, we allow the process to
! 1381: * continue. I'm not sure if that's right. */
! 1382: ret = system(cmd_buf);
! 1383: if (ret)
! 1384: _exit(ret);
! 1385: }
! 1386: #endif
! 1387:
! 1388:
! 1389: int main(int argc,char *argv[])
! 1390: {
! 1391: int ret;
! 1392: int orig_argc = argc;
! 1393: char **orig_argv = argv;
! 1394: #ifdef HAVE_SIGACTION
! 1395: # ifdef HAVE_SIGPROCMASK
! 1396: sigset_t sigmask;
! 1397:
! 1398: sigemptyset(&sigmask);
! 1399: # endif
! 1400: sigact.sa_flags = SA_NOCLDSTOP;
! 1401: #endif
! 1402: SIGACTMASK(SIGUSR1, sigusr1_handler);
! 1403: SIGACTMASK(SIGUSR2, sigusr2_handler);
! 1404: SIGACTMASK(SIGCHLD, remember_children);
! 1405: #ifdef MAINTAINER_MODE
! 1406: SIGACTMASK(SIGSEGV, rsync_panic_handler);
! 1407: SIGACTMASK(SIGFPE, rsync_panic_handler);
! 1408: SIGACTMASK(SIGABRT, rsync_panic_handler);
! 1409: SIGACTMASK(SIGBUS, rsync_panic_handler);
! 1410: #endif
! 1411:
! 1412: starttime = time(NULL);
! 1413: our_uid = MY_UID();
! 1414: am_root = our_uid == 0;
! 1415:
! 1416: memset(&stats, 0, sizeof(stats));
! 1417:
! 1418: if (argc < 2) {
! 1419: usage(FERROR);
! 1420: exit_cleanup(RERR_SYNTAX);
! 1421: }
! 1422:
! 1423: /* we set a 0 umask so that correct file permissions can be
! 1424: * carried across */
! 1425: orig_umask = umask(0);
! 1426:
! 1427: #if defined CONFIG_LOCALE && defined HAVE_SETLOCALE
! 1428: setlocale(LC_CTYPE, "");
! 1429: #endif
! 1430:
! 1431: if (!parse_arguments(&argc, (const char ***) &argv)) {
! 1432: /* FIXME: We ought to call the same error-handling
! 1433: * code here, rather than relying on getopt. */
! 1434: option_error();
! 1435: exit_cleanup(RERR_SYNTAX);
! 1436: }
! 1437:
! 1438: SIGACTMASK(SIGINT, sig_int);
! 1439: SIGACTMASK(SIGHUP, sig_int);
! 1440: SIGACTMASK(SIGTERM, sig_int);
! 1441: #if defined HAVE_SIGACTION && HAVE_SIGPROCMASK
! 1442: sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
! 1443: #endif
! 1444:
! 1445: /* Ignore SIGPIPE; we consistently check error codes and will
! 1446: * see the EPIPE. */
! 1447: SIGACTION(SIGPIPE, SIG_IGN);
! 1448: #ifdef SIGXFSZ
! 1449: SIGACTION(SIGXFSZ, SIG_IGN);
! 1450: #endif
! 1451:
! 1452: /* Initialize change_dir() here because on some old systems getcwd
! 1453: * (implemented by forking "pwd" and reading its output) doesn't
! 1454: * work when there are other child processes. Also, on all systems
! 1455: * that implement getcwd that way "pwd" can't be found after chroot. */
! 1456: change_dir(NULL, CD_NORMAL);
! 1457:
! 1458: init_flist();
! 1459:
! 1460: if ((write_batch || read_batch) && !am_server) {
! 1461: if (write_batch)
! 1462: write_batch_shell_file(orig_argc, orig_argv, argc);
! 1463:
! 1464: if (read_batch && strcmp(batch_name, "-") == 0)
! 1465: batch_fd = STDIN_FILENO;
! 1466: else {
! 1467: batch_fd = do_open(batch_name,
! 1468: write_batch ? O_WRONLY | O_CREAT | O_TRUNC
! 1469: : O_RDONLY, S_IRUSR | S_IWUSR);
! 1470: }
! 1471: if (batch_fd < 0) {
! 1472: rsyserr(FERROR, errno, "Batch file %s open error",
! 1473: full_fname(batch_name));
! 1474: exit_cleanup(RERR_FILEIO);
! 1475: }
! 1476: if (read_batch)
! 1477: read_stream_flags(batch_fd);
! 1478: else
! 1479: write_stream_flags(batch_fd);
! 1480: }
! 1481: if (write_batch < 0)
! 1482: dry_run = 1;
! 1483:
! 1484: if (am_server) {
! 1485: #ifdef ICONV_CONST
! 1486: setup_iconv();
! 1487: #endif
! 1488: } else if (am_daemon)
! 1489: return daemon_main();
! 1490:
! 1491: if (am_server && protect_args) {
! 1492: char buf[MAXPATHLEN];
! 1493: protect_args = 2;
! 1494: read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL);
! 1495: if (!parse_arguments(&argc, (const char ***) &argv)) {
! 1496: option_error();
! 1497: exit_cleanup(RERR_SYNTAX);
! 1498: }
! 1499: }
! 1500:
! 1501: if (argc < 1) {
! 1502: usage(FERROR);
! 1503: exit_cleanup(RERR_SYNTAX);
! 1504: }
! 1505:
! 1506: if (am_server) {
! 1507: set_nonblocking(STDIN_FILENO);
! 1508: set_nonblocking(STDOUT_FILENO);
! 1509: if (am_daemon)
! 1510: return start_daemon(STDIN_FILENO, STDOUT_FILENO);
! 1511: start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);
! 1512: }
! 1513:
! 1514: ret = start_client(argc, argv);
! 1515: if (ret == -1)
! 1516: exit_cleanup(RERR_STARTCLIENT);
! 1517: else
! 1518: exit_cleanup(ret);
! 1519:
! 1520: return ret;
! 1521: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>