X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3f0211b63a6cdc4a2cecfd2a0dffeba172c86a47..d48810ba5b0b8d09b272092a70da1255c2346ab8:/main.c diff --git a/main.c b/main.c index 4c040b99..5985f808 100644 --- a/main.c +++ b/main.c @@ -4,7 +4,7 @@ * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2003-2007 Wayne Davison + * Copyright (C) 2003-2008 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,6 +45,7 @@ extern int got_xfer_error; extern int module_id; extern int copy_links; extern int copy_dirlinks; +extern int copy_unsafe_links; extern int keep_dirlinks; extern int preserve_hard_links; extern int protocol_version; @@ -63,10 +64,13 @@ extern int read_batch; extern int write_batch; extern int batch_fd; extern int filesfrom_fd; +extern int connect_timeout; extern pid_t cleanup_child_pid; +extern unsigned int module_dirlen; extern struct stats stats; extern char *filesfrom_host; extern char *partial_dir; +extern char *dest_option; extern char *basis_dir[]; extern char *rsync_path; extern char *shell_cmd; @@ -74,11 +78,9 @@ extern char *batch_name; extern char *password_file; extern char curr_dir[MAXPATHLEN]; extern struct file_list *first_flist; -extern struct filter_list_struct server_filter_list; -#ifdef ICONV_OPTION -extern iconv_t ic_send; -#endif +extern struct filter_list_struct daemon_filter_list; +uid_t our_uid; int local_server = 0; int daemon_over_rsh = 0; mode_t orig_umask = 0; @@ -275,7 +277,7 @@ static void output_summary(void) rprintf(FINFO, "total size is %s speedup is %.2f%s\n", human_num(stats.total_size), (double)stats.total_size / (total_written+total_read), - dry_run ? " (DRY RUN)" : ""); + write_batch < 0 ? " (BATCH ONLY)" : dry_run ? " (DRY RUN)" : ""); } fflush(stdout); @@ -329,8 +331,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in { int i, argc = 0; char *args[MAX_ARGS]; - pid_t ret; - char *dir = NULL; + pid_t pid; int dash_l_set = 0; if (!read_batch && !local_server) { @@ -340,7 +341,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in cmd = rsh_env; if (!cmd) cmd = RSYNC_RSH; - cmd = strdup(cmd); + cmd = strdup(cmd); /* MEMORY LEAK */ if (!cmd) goto oom; @@ -449,7 +450,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in batch_gen_fd = from_gen_pipe[0]; *f_out_p = from_gen_pipe[1]; *f_in_p = batch_fd; - ret = -1; /* no child pid */ + pid = (pid_t)-1; /* no child pid */ #ifdef ICONV_CONST setup_iconv(); #endif @@ -459,57 +460,20 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in if (whole_file < 0 && !write_batch) whole_file = 1; set_allow_inc_recurse(); - ret = local_child(argc, args, f_in_p, f_out_p, child_main); + pid = local_child(argc, args, f_in_p, f_out_p, child_main); #ifdef ICONV_CONST setup_iconv(); #endif } else { + pid = piped_child(args, f_in_p, f_out_p); #ifdef ICONV_CONST setup_iconv(); #endif - if (protect_args) { - int fd; -#ifdef ICONV_OPTION - int convert = ic_send != (iconv_t)-1; - xbuf outbuf, inbuf; - - if (convert) - alloc_xbuf(&outbuf, 1024); -#endif - - ret = piped_child(args, f_in_p, f_out_p); - - for (i = 0; args[i]; i++) {} /* find first NULL */ - args[i] = "rsync"; /* set a new arg0 */ - if (verbose > 1) - print_child_argv("protected args:", args + i + 1); - fd = *f_out_p; - do { -#ifdef ICONV_OPTION - if (convert) { - INIT_XBUF_STRLEN(inbuf, args[i]); - iconvbufs(ic_send, &inbuf, &outbuf, - ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE); - outbuf.buf[outbuf.len] = '\0'; - write_buf(fd, outbuf.buf, outbuf.len + 1); - outbuf.len = 0; - } else -#endif - write_buf(fd, args[i], strlen(args[i]) + 1); - } while (args[++i]); - write_byte(fd, 0); -#ifdef ICONV_OPTION - if (convert) - free(outbuf.buf); -#endif - } else - ret = piped_child(args, f_in_p, f_out_p); + if (protect_args) + send_protected_args(*f_out_p, args); } - if (dir) - free(dir); - - return ret; + return pid; oom: out_of_memory("do_cmd"); @@ -543,6 +507,14 @@ static char *get_local_name(struct file_list *flist, char *dest_path) if (!dest_path || list_only) return NULL; + if (daemon_filter_list.head + && (check_filter(&daemon_filter_list, dest_path, 0 != 0) < 0 + || check_filter(&daemon_filter_list, dest_path, 1 != 0) < 0)) { + rprintf(FERROR, "skipping daemon-excluded destination \"%s\"\n", + dest_path); + exit_cleanup(RERR_FILESELECT); + } + /* See what currently exists at the destination. */ if ((statret = do_stat(dest_path, &st)) == 0) { /* If the destination is a dir, enter it and use mode 1. */ @@ -637,36 +609,41 @@ static char *get_local_name(struct file_list *flist, char *dest_path) return cp + 1; } -/* Call this if the destination dir (which is assumed to be in curr_dir) - * does not yet exist and we can't create it due to being in dry-run - * mode. We'll fix dirs that can be relative to the non-existent dir. */ -static void fix_basis_dirs(void) +/* This function checks on our alternate-basis directories. If we're in + * dry-run mode and the destination dir does not yet exist, we'll try to + * tweak any dest-relative paths to make them work for a dry-run (the + * destination dir must be in curr_dir[] when this function is called). + * We also warn about any arg that is non-existent or not a directory. */ +static void check_alt_basis_dirs(void) { - char **dir, *new, *slash; - int len; - - if (dry_run <= 1) - return; - - slash = strrchr(curr_dir, '/'); - - for (dir = basis_dir; *dir; dir++) { - if (**dir == '/') - continue; - len = curr_dir_len + 1 + strlen(*dir) + 1; - if (!(new = new_array(char, len))) - out_of_memory("fix_basis_dirs"); - if (slash && strncmp(*dir, "../", 3) == 0) { - /* We want to remove only one leading "../" prefix for - * the directory we couldn't create in dry-run mode: - * this ensures that any other ".." references get - * evaluated the same as they would for a live copy. */ - *slash = '\0'; - pathjoin(new, len, curr_dir, *dir + 3); - *slash = '/'; - } else - pathjoin(new, len, curr_dir, *dir); - *dir = new; + STRUCT_STAT st; + char **dir_p, *slash = strrchr(curr_dir, '/'); + + for (dir_p = basis_dir; *dir_p; dir_p++) { + if (dry_run > 1 && **dir_p != '/') { + int len = curr_dir_len + 1 + strlen(*dir_p) + 1; + char *new = new_array(char, len); + if (!new) + out_of_memory("check_alt_basis_dirs"); + if (slash && strncmp(*dir_p, "../", 3) == 0) { + /* We want to remove only one leading "../" prefix for + * the directory we couldn't create in dry-run mode: + * this ensures that any other ".." references get + * evaluated the same as they would for a live copy. */ + *slash = '\0'; + pathjoin(new, len, curr_dir, *dir_p + 3); + *slash = '/'; + } else + pathjoin(new, len, curr_dir, *dir_p); + *dir_p = new; + } + if (do_stat(*dir_p, &st) < 0) { + rprintf(FWARNING, "%s arg does not exist: %s\n", + dest_option, *dir_p); + } else if (!S_ISDIR(st.st_mode)) { + rprintf(FWARNING, "%s arg is not a dir: %s\n", + dest_option, *dir_p); + } } } @@ -754,7 +731,7 @@ static int do_recv(int f_in, int f_out, char *local_name) /* The receiving side mustn't obey this, or an existing symlink that * points to an identical file won't be replaced by the referent. */ - copy_links = copy_dirlinks = 0; + copy_links = copy_dirlinks = copy_unsafe_links = 0; #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && !inc_recurse) @@ -862,7 +839,6 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[]) int exit_code; struct file_list *flist; char *local_name = NULL; - char *dir = NULL; int save_verbose = verbose; if (filesfrom_fd >= 0) { @@ -883,7 +859,7 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[]) } if (argc > 0) { - dir = argv[0]; + char *dir = argv[0]; argc--; argv++; if (!am_daemon && !push_dir(dir, 0)) { @@ -924,26 +900,27 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[]) /* Now that we know what our destination directory turned out to be, * we can sanitize the --link-/copy-/compare-dest args correctly. */ if (sanitize_paths) { - char **dir; - for (dir = basis_dir; *dir; dir++) { - *dir = sanitize_path(NULL, *dir, NULL, curr_dir_depth); - } - if (partial_dir) { - partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth); - } + char **dir_p; + for (dir_p = basis_dir; *dir_p; dir_p++) + *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT); + if (partial_dir) + partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT); } - fix_basis_dirs(); + check_alt_basis_dirs(); - if (server_filter_list.head) { - char **dir; - struct filter_list_struct *elp = &server_filter_list; + if (daemon_filter_list.head) { + char **dir_p; + struct filter_list_struct *elp = &daemon_filter_list; - for (dir = basis_dir; *dir; dir++) { - if (check_filter(elp, *dir, 1) < 0) + for (dir_p = basis_dir; *dir_p; dir_p++) { + char *dir = *dir_p; + if (*dir == '/') + dir += module_dirlen; + if (check_filter(elp, dir, 1) < 0) goto options_rejected; } if (partial_dir && *partial_dir == '/' - && check_filter(elp, partial_dir, 1) < 0) { + && check_filter(elp, partial_dir + module_dirlen, 1) < 0) { options_rejected: rprintf(FERROR, "Your options have been rejected by the server.\n"); @@ -1082,7 +1059,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) if (flist && flist->used > 0) { local_name = get_local_name(flist, argv[0]); - fix_basis_dirs(); + check_alt_basis_dirs(); exit_code2 = do_recv(f_in, f_out, local_name); } else { @@ -1264,6 +1241,12 @@ static int start_client(int argc, char *argv[]) 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) { @@ -1417,7 +1400,8 @@ int main(int argc,char *argv[]) #endif starttime = time(NULL); - am_root = (MY_UID() == 0); + our_uid = MY_UID(); + am_root = our_uid == 0; memset(&stats, 0, sizeof(stats)); @@ -1434,7 +1418,7 @@ int main(int argc,char *argv[]) setlocale(LC_CTYPE, ""); #endif - if (!parse_arguments(&argc, (const char ***) &argv, 1)) { + 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(); @@ -1499,7 +1483,7 @@ int main(int argc,char *argv[]) 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, 1)) { + if (!parse_arguments(&argc, (const char ***) &argv)) { option_error(); exit_cleanup(RERR_SYNTAX); }