📄 main.c
字号:
io_start_buffering_out(f_out); if (!filesfrom_host) set_msg_fd_in(f_in); send_filter_list(f_out); if (filesfrom_host) filesfrom_fd = f_in; if (write_batch && !am_server) start_write_batch(f_out); flist = send_file_list(f_out, argc, argv); set_msg_fd_in(-1); if (verbose > 3) rprintf(FINFO,"file list sent\n"); if (protocol_version >= 23) io_start_multiplex_in(); io_flush(NORMAL_FLUSH); send_files(f_in, f_out); io_flush(FULL_FLUSH); handle_stats(-1); if (protocol_version >= 24) read_final_goodbye(f_in); if (pid != -1) { if (verbose > 3) rprintf(FINFO,"client_run waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process_with_flush(pid, &exit_code); } output_summary(); io_flush(FULL_FLUSH); exit_cleanup(exit_code); } if (!read_batch) { if (protocol_version >= 23) io_start_multiplex_in(); if (need_messages_from_generator) io_start_multiplex_out(); } send_filter_list(read_batch ? -1 : f_out); if (filesfrom_fd >= 0) { io_set_filesfrom_fds(filesfrom_fd, f_out); filesfrom_fd = -1; } if (write_batch && !am_server) start_write_batch(f_in); flist = recv_file_list(f_in); if (inc_recurse && file_total == 1) recv_additional_file_list(f_in); if (flist && flist->used > 0) { local_name = get_local_name(flist, argv[0]); check_alt_basis_dirs(); exit_code2 = do_recv(f_in, f_out, local_name); } else { handle_stats(-1); output_summary(); } if (pid != -1) { if (verbose > 3) rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process_with_flush(pid, &exit_code); } return MAX(exit_code, exit_code2);}static int copy_argv(char *argv[]){ int i; for (i = 0; argv[i]; i++) { if (!(argv[i] = strdup(argv[i]))) { rprintf (FERROR, "out of memory at %s(%d)\n", __FILE__, __LINE__); return RERR_MALLOC; } } return 0;}/** * Start a client for either type of remote connection. Work out * whether the arguments request a remote shell or rsyncd connection, * and call the appropriate connection function, then run_client. * * Calls either start_socket_client (for sockets) or do_cmd and * client_run (for ssh). **/static int start_client(int argc, char *argv[]){ char *p, *shell_machine = NULL, *shell_user = NULL; char **remote_argv; int remote_argc; int f_in, f_out; int ret; pid_t pid; /* Don't clobber argv[] so that ps(1) can still show the right * command line. */ if ((ret = copy_argv(argv)) != 0) return ret; if (!read_batch) { /* for read_batch, NO source is specified */ char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); if (path) { /* source is remote */ char *dummy_host; int dummy_port = 0; *argv = path; remote_argv = argv; remote_argc = argc; argv += argc - 1; if (argc == 1 || **argv == ':') argc = 0; /* no dest arg */ else if (check_for_hostspec(*argv, &dummy_host, &dummy_port)) { rprintf(FERROR, "The source and destination cannot both be remote.\n"); exit_cleanup(RERR_SYNTAX); } else { remote_argc--; /* don't count dest */ argc = 1; } if (filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } am_sender = 0; if (rsync_port) daemon_over_rsh = shell_cmd ? 1 : -1; } else { /* source is local, check dest arg */ am_sender = 1; if (argc > 1) { p = argv[--argc]; remote_argv = argv + argc; } else { static char *dotarg[1] = { "." }; p = dotarg[0]; remote_argv = dotarg; } remote_argc = 1; path = check_for_hostspec(p, &shell_machine, &rsync_port); if (path && filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } if (!path) { /* no hostspec found, so src & dest are local */ local_server = 1; if (filesfrom_host) { rprintf(FERROR, "--files-from cannot be remote when the transfer is local\n"); exit_cleanup(RERR_SYNTAX); } shell_machine = NULL; } else { /* hostspec was found, so dest is remote */ argv[argc] = path; if (rsync_port) daemon_over_rsh = shell_cmd ? 1 : -1; } } } else { /* read_batch */ local_server = 1; if (check_for_hostspec(argv[argc-1], &shell_machine, &rsync_port)) { rprintf(FERROR, "remote destination is not allowed with --read-batch\n"); exit_cleanup(RERR_SYNTAX); } remote_argv = argv += argc - 1; remote_argc = argc = 1; } if (am_sender) { char *dummy_host; int dummy_port = rsync_port; int i; /* For local source, extra source args must not have hostspec. */ for (i = 1; i < argc; i++) { if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) { rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]); exit_cleanup(RERR_SYNTAX); } } } else { char *dummy_host; int dummy_port = rsync_port; int i; /* For remote source, any extra source args must have either * the same hostname or an empty hostname. */ for (i = 1; i < remote_argc; i++) { char *arg = check_for_hostspec(remote_argv[i], &dummy_host, &dummy_port); if (!arg) { rprintf(FERROR, "Unexpected local arg: %s\n", remote_argv[i]); rprintf(FERROR, "If arg is a remote file/dir, prefix it with a colon (:).\n"); exit_cleanup(RERR_SYNTAX); } if (*dummy_host && strcmp(dummy_host, shell_machine) != 0) { rprintf(FERROR, "All source args must come from the same machine.\n"); exit_cleanup(RERR_SYNTAX); } if (rsync_port != dummy_port) { if (!rsync_port || !dummy_port) rprintf(FERROR, "All source args must use the same hostspec format.\n"); else rprintf(FERROR, "All source args must use the same port number.\n"); exit_cleanup(RERR_SYNTAX); } remote_argv[i] = arg; } } if (daemon_over_rsh < 0) return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv); if (password_file && !daemon_over_rsh) { rprintf(FERROR, "The --password-file option may only be " "used when accessing an rsync daemon.\n"); exit_cleanup(RERR_SYNTAX); } if (connect_timeout) { rprintf(FERROR, "The --contimeout option may only be " "used when connecting to an rsync daemon.\n"); exit_cleanup(RERR_SYNTAX); } if (shell_machine) { p = strrchr(shell_machine,'@'); if (p) { *p = 0; shell_user = shell_machine; shell_machine = p+1; } } if (verbose > 3) { rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n", NS(shell_cmd), NS(shell_machine), NS(shell_user), remote_argv ? NS(remote_argv[0]) : ""); } pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc, &f_in, &f_out); /* if we're running an rsync server on the remote host over a * remote shell command, we need to do the RSYNCD protocol first */ if (daemon_over_rsh) { int tmpret; tmpret = start_inband_exchange(f_in, f_out, shell_user, remote_argc, remote_argv); if (tmpret < 0) return tmpret; } ret = client_run(f_in, f_out, pid, argc, argv); fflush(stdout); fflush(stderr); return ret;}static RETSIGTYPE sigusr1_handler(UNUSED(int val)){ exit_cleanup(RERR_SIGNAL1);}static RETSIGTYPE sigusr2_handler(UNUSED(int val)){ if (!am_server) output_summary(); close_all(); if (got_xfer_error) _exit(RERR_PARTIAL); _exit(0);}RETSIGTYPE remember_children(UNUSED(int val)){#ifdef WNOHANG int cnt, status; pid_t pid; /* An empty waitpid() loop was put here by Tridge and we could never * get him to explain why he put it in, so rather than taking it * out we're instead saving the child exit statuses for later use. * The waitpid() loop presumably eliminates all possibility of leaving * zombie children, maybe that's why he did it. */ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { /* save the child's exit status */ for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) { if (pid_stat_table[cnt].pid == 0) { pid_stat_table[cnt].pid = pid; pid_stat_table[cnt].status = status; break; } } }#endif#ifndef HAVE_SIGACTION signal(SIGCHLD, remember_children);#endif}/** * This routine catches signals and tries to send them to gdb. * * Because it's called from inside a signal handler it ought not to * use too many library routines. * * @todo Perhaps use "screen -X" instead/as well, to help people * debugging without easy access to X. Perhaps use an environment * variable, or just call a script? * * @todo The /proc/ magic probably only works on Linux (and * Solaris?) Can we be more portable? **/#ifdef MAINTAINER_MODEconst char *get_panic_action(void){ const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION"); if (cmd_fmt) return cmd_fmt; else return "xterm -display :0 -T Panic -n Panic " "-e gdb /proc/%d/exe %d";}/** * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION. * * This signal handler is only installed if we were configured with * --enable-maintainer-mode. Perhaps it should always be on and we * should just look at the environment variable, but I'm a bit leery * of a signal sending us into a busy loop. **/static RETSIGTYPE rsync_panic_handler(UNUSED(int whatsig)){ char cmd_buf[300]; int ret; snprintf(cmd_buf, sizeof cmd_buf, get_panic_action(), getpid(), getpid()); /* Unless we failed to execute gdb, we allow the process to * continue. I'm not sure if that's right. */ ret = system(cmd_buf); if (ret) _exit(ret);}#endifint main(int argc,char *argv[]){ int ret; int orig_argc = argc; char **orig_argv = argv;#ifdef HAVE_SIGACTION# ifdef HAVE_SIGPROCMASK sigset_t sigmask; sigemptyset(&sigmask);# endif sigact.sa_flags = SA_NOCLDSTOP;#endif SIGACTMASK(SIGUSR1, sigusr1_handler); SIGACTMASK(SIGUSR2, sigusr2_handler); SIGACTMASK(SIGCHLD, remember_children);#ifdef MAINTAINER_MODE SIGACTMASK(SIGSEGV, rsync_panic_handler); SIGACTMASK(SIGFPE, rsync_panic_handler); SIGACTMASK(SIGABRT, rsync_panic_handler); SIGACTMASK(SIGBUS, rsync_panic_handler);#endif starttime = time(NULL); our_uid = MY_UID(); am_root = our_uid == 0; memset(&stats, 0, sizeof(stats)); if (argc < 2) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } /* we set a 0 umask so that correct file permissions can be * carried across */ orig_umask = umask(0);#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE setlocale(LC_CTYPE, "");#endif if (!parse_arguments(&argc, (const char ***) &argv)) { /* FIXME: We ought to call the same error-handling * code here, rather than relying on getopt. */ option_error(); exit_cleanup(RERR_SYNTAX); } SIGACTMASK(SIGINT, sig_int); SIGACTMASK(SIGHUP, sig_int); SIGACTMASK(SIGTERM, sig_int);#if defined HAVE_SIGACTION && HAVE_SIGPROCMASK sigprocmask(SIG_UNBLOCK, &sigmask, NULL);#endif /* Ignore SIGPIPE; we consistently check error codes and will * see the EPIPE. */ SIGACTION(SIGPIPE, SIG_IGN);#ifdef SIGXFSZ SIGACTION(SIGXFSZ, SIG_IGN);#endif /* Initialize change_dir() here because on some old systems getcwd * (implemented by forking "pwd" and reading its output) doesn't * work when there are other child processes. Also, on all systems * that implement getcwd that way "pwd" can't be found after chroot. */ change_dir(NULL, CD_NORMAL); init_flist(); if ((write_batch || read_batch) && !am_server) { if (write_batch) write_batch_shell_file(orig_argc, orig_argv, argc); if (read_batch && strcmp(batch_name, "-") == 0) batch_fd = STDIN_FILENO; else { batch_fd = do_open(batch_name, write_batch ? O_WRONLY | O_CREAT | O_TRUNC : O_RDONLY, S_IRUSR | S_IWUSR); } if (batch_fd < 0) { rsyserr(FERROR, errno, "Batch file %s open error", full_fname(batch_name)); exit_cleanup(RERR_FILEIO); } if (read_batch) read_stream_flags(batch_fd); else write_stream_flags(batch_fd); } if (write_batch < 0) dry_run = 1; if (am_server) {#ifdef ICONV_CONST setup_iconv();#endif } else if (am_daemon) return daemon_main(); if (am_server && protect_args) { char buf[MAXPATHLEN]; protect_args = 2; read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL); if (!parse_arguments(&argc, (const char ***) &argv)) { option_error(); exit_cleanup(RERR_SYNTAX); } } if (argc < 1) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } if (am_server) { set_nonblocking(STDIN_FILENO); set_nonblocking(STDOUT_FILENO); if (am_daemon) return start_daemon(STDIN_FILENO, STDOUT_FILENO); start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv); } ret = start_client(argc, argv); if (ret == -1) exit_cleanup(RERR_STARTCLIENT); else exit_cleanup(ret); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -