X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/82f0c63e8a94fc095d9b9507ad963a411625a0c7..595251de24388fdfbac120daf9f3a748745ef7c5:/main.c diff --git a/main.c b/main.c index 835a9cde..e8b5efd3 100644 --- a/main.c +++ b/main.c @@ -68,6 +68,15 @@ struct file_list *the_file_list; * but set it higher, just in case. */ #define MAXCHILDPROCS 7 +#ifdef HAVE_SIGACTION +# ifdef HAVE_SIGPROCMASK +# define SIGACTMASK(n,h) SIGACTION(n,h), sigaddset(&sigmask,(n)) +# else +# define SIGACTMASK(n,h) SIGACTION(n,h) +# endif +static struct sigaction sigact; +#endif + struct pid_status { pid_t pid; int status; @@ -393,7 +402,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path, if (verbose > 3) { for (i = 0; i < argc; i++) - rprintf(FINFO, "cmd[%d]=%s ", i, safe_fname(args[i])); + rprintf(FINFO, "cmd[%d]=%s ", i, args[i]); rprintf(FINFO, "\n"); } @@ -426,57 +435,108 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path, return 0; /* not reached */ } - -static char *get_local_name(struct file_list *flist,char *name) +/* The receiving side operates in one of two modes: + * + * 1. it enters a directory and receives one or more files, placing them + * according to their names in the file-list. + * + * 2. it receives a single file and saves it using the name in the + * destination path instead of its file-list name. This requires a + * "local name" for writing out the destination file. + * + * So, our task is to figure out what mode/local-name we need and return + * either a NULL for mode 1, or the local-name for mode 2. We also + * change directory if there are any path components in dest_path. */ +static char *get_local_name(struct file_list *flist, char *dest_path) { STRUCT_STAT st; - int e; + char *cp; - if (verbose > 2) - rprintf(FINFO,"get_local_name count=%d %s\n", - flist->count, NS(name)); + if (verbose > 2) { + rprintf(FINFO, "get_local_name count=%d %s\n", + flist->count, NS(dest_path)); + } - if (!name) + if (!dest_path) return NULL; - if (do_stat(name,&st) == 0) { + /* If the destination path refers to an existing directory, enter + * it and use mode 1. If there is something other than a directory + * at the destination path, we must be transferring one file + * (anything at the destination will be overwritten). */ + if (do_stat(dest_path, &st) == 0) { if (S_ISDIR(st.st_mode)) { - if (!push_dir(name)) { + if (!push_dir(dest_path)) { rsyserr(FERROR, errno, "push_dir#1 %s failed", - full_fname(name)); + full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } return NULL; } if (flist->count > 1) { - rprintf(FERROR,"ERROR: destination must be a directory when copying more than 1 file\n"); + rprintf(FERROR, + "ERROR: destination must be a directory when" + " copying more than 1 file\n"); exit_cleanup(RERR_FILESELECT); } - return name; } - if (flist->count <= 1 && ((e = strlen(name)) <= 1 || name[e-1] != '/')) - return name; + cp = strrchr(dest_path, '/'); - if (do_mkdir(name,0777 & ~orig_umask) != 0) { - rsyserr(FERROR, errno, "mkdir %s failed", full_fname(name)); - exit_cleanup(RERR_FILEIO); - } - if (verbose > 0) - rprintf(FINFO, "created directory %s\n", safe_fname(name)); + /* If the destination path ends in a slash or we are transferring + * multiple files, create a directory at the destination path, + * enter the new directory, and use mode 1. */ + if (flist->count > 1 || (cp && !cp[1])) { + /* Lop off the final slash (if any). */ + if (cp && !cp[1]) + *cp = '\0'; + + umask(orig_umask); + if (do_mkdir(dest_path, 0777) != 0) { + rsyserr(FERROR, errno, "mkdir %s failed", + full_fname(dest_path)); + exit_cleanup(RERR_FILEIO); + } + umask(0); + + if (verbose) + rprintf(FINFO, "created directory %s\n", dest_path); + + if (dry_run) { + /* Indicate that the destination directory doesn't + * really exist and return mode 1. */ + dry_run++; + return NULL; + } + + if (!push_dir(dest_path)) { + rsyserr(FERROR, errno, "push_dir#2 %s failed", + full_fname(dest_path)); + exit_cleanup(RERR_FILESELECT); + } - if (dry_run) { - dry_run++; return NULL; } - if (!push_dir(name)) { - rsyserr(FERROR, errno, "push_dir#2 %s failed", - full_fname(name)); + /* Otherwise, we are writing a single file, possibly on top of an + * existing non-directory. Change to the item's parent directory + * (if it has a path component), return the basename of the + * destination file as the local name, and use mode 2. */ + if (!cp) + return dest_path; + + if (cp == dest_path) + dest_path = "/"; + + *cp = '\0'; + if (!push_dir(dest_path)) { + rsyserr(FERROR, errno, "push_dir#3 %s failed", + full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } + *cp = '/'; - return NULL; + return cp + 1; } @@ -504,7 +564,7 @@ static void read_final_goodbye(int f_in, int f_out) } -static void do_server_sender(int f_in, int f_out, int argc,char *argv[]) +static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) { struct file_list *flist; char *dir = argv[0]; @@ -732,6 +792,9 @@ void start_server(int f_in, int f_out, int argc, char *argv[]) io_set_sock_fds(f_in, f_out); setup_protocol(f_out, f_in); +#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H + setup_iconv(); +#endif if (protocol_version >= 23) io_start_multiplex_out(); @@ -768,6 +831,9 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) io_set_sock_fds(f_in, f_out); setup_protocol(f_out,f_in); +#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H + setup_iconv(); +#endif if (protocol_version >= 23 && !read_batch) io_start_multiplex_in(); @@ -974,10 +1040,10 @@ static int start_client(int argc, char *argv[]) if (verbose > 3) { rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n", - shell_cmd ? safe_fname(shell_cmd) : "", - shell_machine ? safe_fname(shell_machine) : "", - shell_user ? safe_fname(shell_user) : "", - shell_path ? safe_fname(shell_path) : ""); + shell_cmd ? shell_cmd : "", + shell_machine ? shell_machine : "", + shell_user ? shell_user : "", + shell_path ? shell_path : ""); } /* for remote source, only single dest arg can remain ... */ @@ -1014,7 +1080,7 @@ static int start_client(int argc, char *argv[]) static RETSIGTYPE sigusr1_handler(UNUSED(int val)) { - exit_cleanup(RERR_SIGNAL); + exit_cleanup(RERR_SIGNAL1); } static RETSIGTYPE sigusr2_handler(UNUSED(int val)) @@ -1048,7 +1114,9 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val)) } } #endif +#ifndef HAVE_SIGACTION signal(SIGCHLD, sigchld_handler); +#endif } @@ -1108,16 +1176,23 @@ int main(int argc,char *argv[]) int ret; int orig_argc = argc; char **orig_argv = argv; +#ifdef HAVE_SIGACTION +# ifdef HAVE_SIGPROCMASK + sigset_t sigmask; - signal(SIGUSR1, sigusr1_handler); - signal(SIGUSR2, sigusr2_handler); - signal(SIGCHLD, sigchld_handler); + sigemptyset(&sigmask); +# endif + sigact.sa_flags = SA_NOCLDSTOP; +#endif + SIGACTMASK(SIGUSR1, sigusr1_handler); + SIGACTMASK(SIGUSR2, sigusr2_handler); + SIGACTMASK(SIGCHLD, sigchld_handler); #ifdef MAINTAINER_MODE - signal(SIGSEGV, rsync_panic_handler); - signal(SIGFPE, rsync_panic_handler); - signal(SIGABRT, rsync_panic_handler); - signal(SIGBUS, rsync_panic_handler); -#endif /* def 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); am_root = (MY_UID() == 0); @@ -1133,6 +1208,10 @@ int main(int argc,char *argv[]) * carried across */ orig_umask = (int)umask(0); +#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE + setlocale(LC_CTYPE, ""); +#endif + if (!parse_arguments(&argc, (const char ***) &argv, 1)) { /* FIXME: We ought to call the same error-handling * code here, rather than relying on getopt. */ @@ -1140,17 +1219,16 @@ int main(int argc,char *argv[]) exit_cleanup(RERR_SYNTAX); } - signal(SIGINT,SIGNAL_CAST sig_int); - signal(SIGHUP,SIGNAL_CAST sig_int); - signal(SIGTERM,SIGNAL_CAST sig_int); + 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. */ - signal(SIGPIPE, SIG_IGN); - -#if defined CONFIG_LOCALE && defined HAVE_SETLOCALE - setlocale(LC_CTYPE, ""); -#endif + SIGACTION(SIGPIPE, SIG_IGN); /* Initialize push_dir here because on some old systems getcwd * (implemented by forking "pwd" and reading its output) doesn't