X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/936fa865e1fd2ea0c97ef1a361f3f35a4153be75..2042c632512e47cb7bfa3aa6131b89c2e9829820:/options.c diff --git a/options.c b/options.c index 32b574e3..65fc9c4a 100644 --- a/options.c +++ b/options.c @@ -20,6 +20,7 @@ */ #include "rsync.h" +#include "ifuncs.h" #include #include "zlib/zlib.h" @@ -56,7 +57,6 @@ int preserve_specials = 0; int preserve_uid = 0; int preserve_gid = 0; int preserve_times = 0; -int omit_dir_times = 0; int update_only = 0; int cvs_exclude = 0; int dry_run = 0; @@ -91,6 +91,7 @@ char *files_from = NULL; int filesfrom_fd = -1; char *filesfrom_host = NULL; int eol_nulls = 0; +int protect_args = 0; int human_readable = 0; int recurse = 0; int allow_inc_recurse = 1; @@ -184,14 +185,15 @@ int list_only = 0; #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */ char *batch_name = NULL; -#ifdef ICONV_OPTION int need_unsorted_flist = 0; +#ifdef ICONV_OPTION char *iconv_opt = ICONV_OPTION; #endif struct chmod_mode_struct *chmod_modes = NULL; static int daemon_opt; /* sets am_daemon after option error-reporting */ +static int omit_dir_times = 0; static int F_option_cnt = 0; static int modify_window_set; static int itemize_changes = 0; @@ -349,7 +351,7 @@ void usage(enum logcode F) rprintf(F," --fake-super store/recover privileged attrs using xattrs\n"); #endif rprintf(F," -S, --sparse handle sparse files efficiently\n"); - rprintf(F," -n, --dry-run show what would have been transferred\n"); + rprintf(F," -n, --dry-run perform a trial run with no changes made\n"); rprintf(F," -W, --whole-file copy files whole (without rsync algorithm)\n"); rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n"); rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n"); @@ -397,6 +399,7 @@ void usage(enum logcode F) rprintf(F," --include-from=FILE read include patterns from FILE\n"); rprintf(F," --files-from=FILE read list of source-file names from FILE\n"); rprintf(F," -0, --from0 all *-from/filter files are delimited by 0s\n"); + rprintf(F," -s, --protect-args no space-splitting; only wildcard special-chars\n"); rprintf(F," --address=ADDRESS bind address for outgoing socket to daemon\n"); rprintf(F," --port=PORT specify double-colon alternate port number\n"); rprintf(F," --sockopts=OPTIONS specify custom TCP options\n"); @@ -418,7 +421,7 @@ void usage(enum logcode F) rprintf(F," --read-batch=FILE read a batched update from FILE\n"); rprintf(F," --protocol=NUM force an older protocol version to be used\n"); #ifdef ICONV_OPTION - rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filesnames\n"); + rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n"); #endif rprintf(F," -4, --ipv4 prefer IPv4\n"); rprintf(F," -6, --ipv6 prefer IPv6\n"); @@ -459,8 +462,8 @@ static struct poptOption long_options[] = { {"no-r", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 }, {"inc-recursive", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 }, {"no-inc-recursive", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 }, - {"ir", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 }, - {"no-ir", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 }, + {"i-r", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 }, + {"no-i-r", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 }, {"dirs", 'd', POPT_ARG_VAL, &xfer_dirs, 2, 0, 0 }, {"no-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 }, {"no-d", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 }, @@ -474,10 +477,12 @@ static struct poptOption long_options[] = { {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 }, {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 }, {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 }, - {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, + {"times", 't', POPT_ARG_VAL, &preserve_times, 2, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, - {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 2, 0, 0 }, + {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, + {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, + {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 }, {"super", 0, POPT_ARG_VAL, &am_root, 2, 0, 0 }, {"no-super", 0, POPT_ARG_VAL, &am_root, 0, 0, 0 }, @@ -510,6 +515,8 @@ static struct poptOption long_options[] = { {"no-R", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 }, {"implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 }, {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 }, + {"i-d", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 }, + {"no-i-d", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 }, {"chmod", 0, POPT_ARG_STRING, 0, OPT_CHMOD, 0, 0 }, {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 }, {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 }, @@ -589,6 +596,9 @@ static struct poptOption long_options[] = { {"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 }, {"from0", '0', POPT_ARG_VAL, &eol_nulls, 1, 0, 0}, {"no-from0", 0, POPT_ARG_VAL, &eol_nulls, 0, 0, 0}, + {"protect-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0}, + {"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, + {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 }, {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 }, {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 }, @@ -854,12 +864,13 @@ static void create_refuse_error(int which) * * @retval 0 on error, with err_buf containing an explanation **/ -int parse_arguments(int *argc, const char ***argv, int frommain) +int parse_arguments(int *argc_p, const char ***argv_p, int frommain) { - int opt; + static poptContext pc; char *ref = lp_refuse_options(module_id); - const char *arg; - poptContext pc; + const char *arg, **argv = *argv_p; + int argc = *argc_p; + int opt; if (ref && *ref) set_refuse_options(ref); @@ -867,7 +878,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) set_refuse_options("log-file*"); #ifdef ICONV_OPTION - if (!am_daemon && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) + if (!am_daemon && !protect_args && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) iconv_opt = strdup(arg); #endif @@ -875,8 +886,11 @@ int parse_arguments(int *argc, const char ***argv, int frommain) /* The context leaks in case of an error, but if there's a * problem we always exit anyhow. */ - pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0); - poptReadDefaultConfig(pc, 0); + if (pc) + poptFreeContext(pc); + pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0); + if (!am_server) + poptReadDefaultConfig(pc, 0); while ((opt = poptGetNextOpt(pc)) != -1) { /* most options are handled automatically by popt; @@ -892,7 +906,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) /* Disable popt aliases on the server side and * then start parsing the options again. */ poptFreeContext(pc); - pc = poptGetContext(RSYNC_NAME, *argc, *argv, + pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0); am_server = 1; } @@ -920,7 +934,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) iconv_opt = NULL; #endif poptFreeContext(pc); - pc = poptGetContext(RSYNC_NAME, *argc, *argv, + pc = poptGetContext(RSYNC_NAME, argc, argv, long_daemon_options, 0); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { @@ -955,8 +969,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain) exit_cleanup(RERR_SYNTAX); } - *argv = poptGetArgs(pc); - *argc = count_args(*argv); + *argv_p = argv = poptGetArgs(pc); + *argc_p = argc = count_args(argv); am_starting_up = 0; daemon_opt = 0; am_daemon = 1; @@ -989,15 +1003,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (sanitize_paths) arg = sanitize_path(NULL, arg, NULL, 0, NULL); if (server_filter_list.head) { + int rej; char *cp = strdup(arg); if (!cp) out_of_memory("parse_arguments"); if (!*cp) goto options_rejected; - clean_fname(cp, 1); - if (check_filter(&server_filter_list, cp, 0) < 0) - goto options_rejected; + clean_fname(cp, CFN_COLLAPSE_DOT_DOT_DIRS); + rej = check_filter(&server_filter_list, cp, 0) < 0; free(cp); + if (rej) + goto options_rejected; } parse_filter_file(&filter_list, arg, opt == OPT_INCLUDE_FROM ? MATCHFLG_INCLUDE : 0, @@ -1015,7 +1031,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) preserve_links = 1; #endif preserve_perms = 1; - preserve_times = 1; + preserve_times = 2; preserve_gid = 1; preserve_uid = 1; preserve_devices = 1; @@ -1184,9 +1200,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain) break; #else /* FIXME: this should probably be ignored with a - * warning and then countermeasures taken to - * restrict group and other access in the presence - * of any more restrictive ACLs, but this is safe + * warning and then countermeasures taken to + * restrict group and other access in the presence + * of any more restrictive ACLs, but this is safe * for now */ snprintf(err_buf,sizeof(err_buf), "ACLs are not supported on this %s\n", @@ -1220,14 +1236,14 @@ int parse_arguments(int *argc, const char ***argv, int frommain) } } - if (human_readable && *argc == 2) { + if (human_readable && argc == 2) { /* Allow the old meaning of 'h' (--help) on its own. */ usage(FINFO); exit_cleanup(0); } #ifdef ICONV_OPTION - if (iconv_opt) { + if (iconv_opt && protect_args != 2) { if (!am_server && strcmp(iconv_opt, "-") == 0) iconv_opt = NULL; else @@ -1235,6 +1251,13 @@ int parse_arguments(int *argc, const char ***argv, int frommain) } #endif + if (protect_args == 1) { + if (!frommain) + protect_args = 0; + else if (am_server) + return 1; + } + #ifndef SUPPORT_LINKS if (preserve_links && !am_sender) { snprintf(err_buf, sizeof err_buf, @@ -1365,13 +1388,13 @@ int parse_arguments(int *argc, const char ***argv, int frommain) need_messages_from_generator = 1; } - *argv = poptGetArgs(pc); - *argc = count_args(*argv); + *argv_p = argv = poptGetArgs(pc); + *argc_p = argc = count_args(argv); if (sanitize_paths) { int i; - for (i = *argc; i-- > 0; ) - (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0, NULL); + for (i = argc; i-- > 0; ) + argv[i] = sanitize_path(NULL, argv[i], "", 0, NULL); if (tmpdir) tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, NULL); if (backup_dir) @@ -1382,14 +1405,14 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (tmpdir) { if (!*tmpdir) goto options_rejected; - clean_fname(tmpdir, 1); + clean_fname(tmpdir, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(elp, tmpdir, 1) < 0) goto options_rejected; } if (backup_dir) { if (!*backup_dir) goto options_rejected; - clean_fname(backup_dir, 1); + clean_fname(backup_dir, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(elp, backup_dir, 1) < 0) goto options_rejected; } @@ -1422,13 +1445,20 @@ int parse_arguments(int *argc, const char ***argv, int frommain) snprintf(err_buf, sizeof err_buf, "--suffix cannot be a null string without --backup-dir\n"); return 0; - } else if (make_backups && delete_mode && !delete_excluded && !am_server) { - snprintf(backup_dir_buf, sizeof backup_dir_buf, + } else if (make_backups && delete_mode && !delete_excluded && !am_server) { + snprintf(backup_dir_buf, sizeof backup_dir_buf, "P *%s", backup_suffix); - parse_rule(&filter_list, backup_dir_buf, 0, 0); + parse_rule(&filter_list, backup_dir_buf, 0, 0); + } + + if (make_backups && !backup_dir) { + omit_dir_times = 0; /* Implied, so avoid -O to sender. */ + if (preserve_times > 1) + preserve_times = 1; + } else if (omit_dir_times) { + if (preserve_times > 1) + preserve_times = 1; } - if (make_backups && !backup_dir) - omit_dir_times = 1; if (stdout_format) { if (am_server && log_format_has(stdout_format, 'I')) @@ -1535,7 +1565,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) } if (partial_dir) { if (*partial_dir) - clean_fname(partial_dir, 1); + clean_fname(partial_dir, CFN_COLLAPSE_DOT_DOT_DIRS); if (!*partial_dir || strcmp(partial_dir, ".") == 0) partial_dir = NULL; if (!partial_dir && refused_partial) { @@ -1549,7 +1579,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (files_from) { char *h, *p; int q; - if (*argc > 2 || (!am_daemon && *argc == 1)) { + if (argc > 2 || (!am_daemon && argc == 1)) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } @@ -1576,7 +1606,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (server_filter_list.head) { if (!*files_from) goto options_rejected; - clean_fname(files_from, 1); + clean_fname(files_from, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(&server_filter_list, files_from, 0) < 0) goto options_rejected; } @@ -1609,23 +1639,19 @@ int parse_arguments(int *argc, const char ***argv, int frommain) * behave, and also filtering out options that are processed only * locally. **/ -void server_options(char **args,int *argc) +void server_options(char **args, int *argc_p) { static char argstr[64]; - int ac = *argc; + int ac = *argc_p; char *arg; - int i, x; - if (blocking_io == -1) - blocking_io = 0; - /* This should always remain first on the server's command-line. */ args[ac++] = "--server"; if (daemon_over_rsh > 0) { args[ac++] = "--daemon"; - *argc = ac; + *argc_p = ac; /* if we're passing --daemon, we're done */ return; } @@ -1635,6 +1661,10 @@ void server_options(char **args,int *argc) x = 1; argstr[0] = '-'; + + if (protect_args) + argstr[x++] = 's'; + for (i = 0; i < verbose; i++) argstr[x++] = 'v'; @@ -1647,14 +1677,15 @@ void server_options(char **args,int *argc) argstr[x++] = 'n'; if (preserve_links) argstr[x++] = 'l'; - if (xfer_dirs > (recurse || !delete_mode || !am_sender ? 1 : 0)) + if ((list_only && !recurse) || xfer_dirs > 1 + || (xfer_dirs && !recurse && delete_mode && am_sender)) argstr[x++] = 'd'; if (am_sender) { if (keep_dirlinks) argstr[x++] = 'K'; if (prune_empty_dirs) argstr[x++] = 'm'; - if (omit_dir_times == 2) + if (omit_dir_times) argstr[x++] = 'O'; } else { if (copy_links) @@ -1717,26 +1748,42 @@ void server_options(char **args,int *argc) if (do_compression) argstr[x++] = 'z'; - /* This is a complete hack - blame Rusty. FIXME! - * This hack is only needed for older rsync versions that - * don't understand the --list-only option. */ - if (list_only == 1 && !recurse) - argstr[x++] = 'r'; - + /* We make use of the -e option to let the server know about any + * pre-release protocol version && our allow_inc_recurse status. */ + set_allow_inc_recurse(); #if SUBPROTOCOL_VERSION != 0 - /* If we're speaking a pre-release version of a protocol, we tell - * the server about this by (ab)using the -e option. */ if (protocol_version == PROTOCOL_VERSION) { x += snprintf(argstr+x, sizeof argstr - x, - "e%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION); - } + "e%d.%d%s", PROTOCOL_VERSION, SUBPROTOCOL_VERSION, + allow_inc_recurse ? "i" : ""); + } else #endif + if (allow_inc_recurse) { + argstr[x++] = 'e'; + argstr[x++] = 'i'; + } argstr[x] = '\0'; if (x != 1) args[ac++] = argstr; +#ifdef ICONV_OPTION + if (iconv_opt) { + char *set = strchr(iconv_opt, ','); + if (set) + set++; + else + set = iconv_opt; + if (asprintf(&arg, "--iconv=%s", set) < 0) + goto oom; + args[ac++] = arg; + } +#endif + + if (protect_args) /* initial args break here */ + args[ac++] = NULL; + if (list_only > 1) args[ac++] = "--list-only"; @@ -1772,19 +1819,6 @@ void server_options(char **args,int *argc) args[ac++] = "--log-format=X"; } -#ifdef ICONV_OPTION - if (iconv_opt) { - char *set = strchr(iconv_opt, ','); - if (set) - set++; - else - set = iconv_opt; - if (asprintf(&arg, "--iconv=%s", set) < 0) - goto oom; - args[ac++] = arg; - } -#endif - if (block_size) { if (asprintf(&arg, "-B%lu", block_size) < 0) goto oom; @@ -1822,7 +1856,7 @@ void server_options(char **args,int *argc) goto oom; args[ac++] = arg; } else if (max_delete == 0) - args[ac++] = "--max_delete=-1"; + args[ac++] = "--max-delete=-1"; if (min_size) { args[ac++] = "--min-size"; args[ac++] = min_size_arg; @@ -1893,8 +1927,8 @@ void server_options(char **args,int *argc) if (numeric_ids) args[ac++] = "--numeric-ids"; - if (!allow_inc_recurse) - args[ac++] = "--no-ir"; + if (use_qsort) + args[ac++] = "--use-qsort"; if (am_sender) { if (ignore_existing) @@ -1942,7 +1976,8 @@ void server_options(char **args,int *argc) if (!relative_paths) args[ac++] = "--no-relative"; } - if (relative_paths && !implied_dirs && !am_sender) + /* It's OK that this checks the upper-bound of the protocol_version. */ + if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30)) args[ac++] = "--no-implied-dirs"; if (fuzzy_basis && am_sender) @@ -1953,7 +1988,7 @@ void server_options(char **args,int *argc) else if (remove_source_files) args[ac++] = "--remove-sent-files"; - *argc = ac; + *argc_p = ac; return; oom: