X-Git-Url: http://git.samba.org/samba.git/?p=rsync.git;a=blobdiff_plain;f=options.c;h=e5b0cb68280ed5e1d5cfea93e314c1c67c74ebe9;hp=9e95c86ac049ad5f33a6e365764371b75f45a433;hb=3e2e4b5a33c72ef428ff40989a1ba03b4d24c9fb;hpb=48b51d0004922cb029c55fe921f5e7df1c0bff23 diff --git a/options.c b/options.c index 9e95c86a..e5b0cb68 100644 --- a/options.c +++ b/options.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2000, 2001, 2002 Martin Pool - * Copyright (C) 2002-2011 Wayne Davison + * Copyright (C) 2002-2019 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 @@ -32,6 +32,8 @@ extern unsigned int module_dirlen; extern filter_rule_list filter_list; extern filter_rule_list daemon_filter_list; +#define NOT_SPECIFIED (-42) + int make_backups = 0; /** @@ -75,7 +77,7 @@ int protocol_version = PROTOCOL_VERSION; int sparse_files = 0; int preallocate_files = 0; int do_compression = 0; -int def_compress_level = Z_DEFAULT_COMPRESSION; +int def_compress_level = NOT_SPECIFIED; int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */ int am_server = 0; int am_sender = 0; @@ -114,8 +116,8 @@ int ignore_existing = 0; int ignore_non_existing = 0; int need_messages_from_generator = 0; int max_delete = INT_MIN; -OFF_T max_size = 0; -OFF_T min_size = 0; +OFF_T max_size = -1; +OFF_T min_size = -1; int ignore_errors = 0; int modify_window = 0; int blocking_io = -1; @@ -123,7 +125,6 @@ int checksum_seed = 0; int inplace = 0; int delay_updates = 0; long block_size = 0; /* "long" because popt can't set an int32. */ -char number_separator; char *skip_compress = NULL; item_list dparam_list = EMPTY_ITEM_LIST; @@ -181,6 +182,7 @@ char *dest_option = NULL; static int remote_option_alloc = 0; int remote_option_cnt = 0; const char **remote_options = NULL; +const char *checksum_choice = NULL; int quiet = 0; int output_motd = 1; @@ -303,6 +305,9 @@ static int refused_partial, refused_progress, refused_delete_before; static int refused_delete_during; static int refused_inplace, refused_no_iconv; static BOOL usermap_via_chown, groupmap_via_chown; +#ifdef HAVE_SETVBUF +static char *outbuf_mode; +#endif static char *bwlimit_arg, *max_size_arg, *min_size_arg; static char tmp_partialdir[] = ".~tmp~"; @@ -407,16 +412,17 @@ static void parse_output_words(struct output_struct *words, short *levels, const char *s; int j, len, lev; - if (!str) - return; - - while (*str) { + for ( ; str; str = s) { if ((s = strchr(str, ',')) != NULL) len = s++ - str; else len = strlen(str); - while (len && isDigit(str+len-1)) - len--; + if (!len) + continue; + if (!isDigit(str)) { + while (len && isDigit(str+len-1)) + len--; + } lev = isDigit(str+len) ? atoi(str+len) : 1; if (lev > MAX_OUT_LEVEL) lev = MAX_OUT_LEVEL; @@ -444,9 +450,6 @@ static void parse_output_words(struct output_struct *words, short *levels, words[j].help, len, str); exit_cleanup(RERR_SYNTAX); } - if (!s) - break; - str = s; } } @@ -609,7 +612,7 @@ static void print_rsync_version(enum logcode f) rprintf(f, "%s version %s protocol version %d%s\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); - rprintf(f, "Copyright (C) 1996-2011 by Andrew Tridgell, Wayne Davison, and others.\n"); + rprintf(f, "Copyright (C) 1996-2019 by Andrew Tridgell, Wayne Davison, and others.\n"); rprintf(f, "Web site: http://rsync.samba.org/\n"); rprintf(f, "Capabilities:\n"); rprintf(f, " %d-bit files, %d-bit inums, %d-bit timestamps, %d-bit long ints,\n", @@ -711,7 +714,7 @@ void usage(enum logcode F) #ifdef SUPPORT_XATTRS rprintf(F," --fake-super store/recover privileged attrs using xattrs\n"); #endif - rprintf(F," -S, --sparse handle sparse files efficiently\n"); + rprintf(F," -S, --sparse turn sequences of nulls into sparse blocks\n"); #ifdef SUPPORT_PREALLOCATION rprintf(F," --preallocate allocate dest files before writing them\n"); #else @@ -719,6 +722,7 @@ void usage(enum logcode F) #endif rprintf(F," -n, --dry-run perform a trial run with no changes made\n"); rprintf(F," -W, --whole-file copy files whole (without delta-xfer algorithm)\n"); + rprintf(F," --checksum-choice=STR choose the checksum algorithms\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"); rprintf(F," -e, --rsh=COMMAND specify the remote shell to use\n"); @@ -753,7 +757,7 @@ void usage(enum logcode F) rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n"); rprintf(F," -M, --remote-option=OPTION send OPTION to the remote side only\n"); rprintf(F," --size-only skip files that match in size\n"); - rprintf(F," --modify-window=NUM compare mod-times with reduced accuracy\n"); + rprintf(F," -@, --modify-window=NUM set the accuracy for mod-time comparisons\n"); rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n"); rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n"); rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n"); @@ -789,6 +793,9 @@ void usage(enum logcode F) rprintf(F," --password-file=FILE read daemon-access password from FILE\n"); rprintf(F," --list-only list the files instead of copying them\n"); rprintf(F," --bwlimit=RATE limit socket I/O bandwidth\n"); +#ifdef HAVE_SETVBUF + rprintf(F," --outbuf=N|L|B set output buffering to None, Line, or Block\n"); +#endif rprintf(F," --write-batch=FILE write a batched update to FILE\n"); rprintf(F," --only-write-batch=FILE like --write-batch but w/o updating destination\n"); rprintf(F," --read-batch=FILE read a batched update from FILE\n"); @@ -796,6 +803,7 @@ void usage(enum logcode F) #ifdef ICONV_OPTION rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n"); #endif + rprintf(F," --checksum-seed=NUM set block/file checksum seed (advanced)\n"); rprintf(F," -4, --ipv4 prefer IPv4\n"); rprintf(F," -6, --ipv6 prefer IPv6\n"); rprintf(F," --version print version number\n"); @@ -865,7 +873,7 @@ static struct poptOption long_options[] = { {"omit-link-times", 'J', POPT_ARG_VAL, &omit_link_times, 1, 0, 0 }, {"no-omit-link-times",0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 }, {"no-J", 0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 }, - {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 }, + {"modify-window", '@', 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 }, {"fake-super", 0, POPT_ARG_VAL, &am_root, -1, 0, 0 }, @@ -947,6 +955,7 @@ static struct poptOption long_options[] = { {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 }, {"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 }, {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 }, + {"checksum-choice", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 }, {"no-W", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 }, {"checksum", 'c', POPT_ARG_VAL, &always_checksum, 1, 0, 0 }, {"no-checksum", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 }, @@ -959,10 +968,12 @@ static struct poptOption long_options[] = { {"no-fuzzy", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 }, {"no-y", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 }, {"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 }, + {"old-compress", 0, POPT_ARG_VAL, &do_compression, 1, 0, 0 }, + {"new-compress", 0, POPT_ARG_VAL, &do_compression, 2, 0, 0 }, {"no-compress", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 }, {"no-z", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 }, {"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 }, - {"compress-level", 0, POPT_ARG_INT, &def_compress_level, 'z', 0, 0 }, + {"compress-level", 0, POPT_ARG_INT, &def_compress_level, 0, 0, 0 }, {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 }, {"progress", 0, POPT_ARG_VAL, &do_progress, 1, 0, 0 }, {"no-progress", 0, POPT_ARG_VAL, &do_progress, 0, 0, 0 }, @@ -1025,6 +1036,9 @@ static struct poptOption long_options[] = { {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 }, {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 }, {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 }, +#ifdef HAVE_SETVBUF + {"outbuf", 0, POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 }, +#endif {"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 }, {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 }, {"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 }, @@ -1267,6 +1281,22 @@ static void create_refuse_error(int which) } } +/* This is used to make sure that --daemon & --server cannot be aliased to + * something else. These options have always disabled popt aliases for the + * parsing of a daemon or server command-line, but we have to make sure that + * these options cannot vanish so that the alias disabling can take effect. */ +static void popt_unalias(poptContext con, const char *opt) +{ + struct poptAlias unalias; + + unalias.longName = opt + 2; /* point past the leading "--" */ + unalias.shortName = '\0'; + unalias.argc = 1; + unalias.argv = new_array(const char*, 1); + unalias.argv[0] = strdup(opt); + + poptAddAlias(con, unalias, 0); +} /** * Process command line arguments. Called on both local and remote. @@ -1283,7 +1313,12 @@ int parse_arguments(int *argc_p, const char ***argv_p) const char *arg, **argv = *argv_p; int argc = *argc_p; int opt; + int orig_protect_args = protect_args; + if (argc == 0) { + strlcpy(err_buf, "argc is zero!\n", sizeof err_buf); + return 0; + } if (ref && *ref) set_refuse_options(ref); if (am_daemon) { @@ -1306,8 +1341,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) if (pc) poptFreeContext(pc); pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0); - if (!am_server) + if (!am_server) { poptReadDefaultConfig(pc, 0); + popt_unalias(pc, "--daemon"); + popt_unalias(pc, "--server"); + } while ((opt = poptGetNextOpt(pc)) != -1) { /* most options are handled automatically by popt; @@ -1534,18 +1572,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) break; case 'z': - if (def_compress_level < Z_DEFAULT_COMPRESSION - || def_compress_level > Z_BEST_COMPRESSION) { - snprintf(err_buf, sizeof err_buf, - "--compress-level value is invalid: %d\n", - def_compress_level); - return 0; - } - do_compression = def_compress_level != Z_NO_COMPRESSION; - if (do_compression && refused_compress) { - create_refuse_error(refused_compress); - return 0; - } + do_compression++; break; case 'M': @@ -1590,7 +1617,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) break; case OPT_MAX_SIZE: - if ((max_size = parse_size_arg(&max_size_arg, 'b')) <= 0) { + if ((max_size = parse_size_arg(&max_size_arg, 'b')) < 0) { snprintf(err_buf, sizeof err_buf, "--max-size value is invalid: %s\n", max_size_arg); @@ -1599,7 +1626,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) break; case OPT_MIN_SIZE: - if ((min_size = parse_size_arg(&min_size_arg, 'b')) <= 0) { + if ((min_size = parse_size_arg(&min_size_arg, 'b')) < 0) { snprintf(err_buf, sizeof err_buf, "--min-size value is invalid: %s\n", min_size_arg); @@ -1814,12 +1841,81 @@ int parse_arguments(int *argc_p, const char ***argv_p) } } + if (checksum_choice && strcmp(checksum_choice, "auto") != 0 && strcmp(checksum_choice, "auto,auto") != 0) { + /* Call this early to verify the args and figure out if we need to force + * --whole-file. Note that the parse function will get called again later, + * just in case an "auto" choice needs to know the protocol_version. */ + if (parse_checksum_choice()) + whole_file = 1; + } else + checksum_choice = NULL; + if (human_readable > 1 && argc == 2 && !am_server) { /* Allow the old meaning of 'h' (--help) on its own. */ usage(FINFO); exit_cleanup(0); } + if (do_compression || def_compress_level != NOT_SPECIFIED) { + if (def_compress_level == NOT_SPECIFIED) + def_compress_level = Z_DEFAULT_COMPRESSION; + else if (def_compress_level < Z_DEFAULT_COMPRESSION || def_compress_level > Z_BEST_COMPRESSION) { + snprintf(err_buf, sizeof err_buf, "--compress-level value is invalid: %d\n", + def_compress_level); + return 0; + } else if (def_compress_level == Z_NO_COMPRESSION) + do_compression = 0; + else if (!do_compression) + do_compression = 1; + if (do_compression && refused_compress) { + create_refuse_error(refused_compress); + return 0; + } +#ifdef EXTERNAL_ZLIB + if (do_compression == 1) { + snprintf(err_buf, sizeof err_buf, + "This rsync lacks old-style --compress due to its external zlib. Try -zz.\n"); + if (am_server) + return 0; + fprintf(stderr, "%s" "Continuing without compression.\n\n", err_buf); + do_compression = 0; + } +#endif + } + +#ifdef HAVE_SETVBUF + if (outbuf_mode && !am_server) { + int mode = *(uchar *)outbuf_mode; + if (islower(mode)) + mode = toupper(mode); + fflush(stdout); /* Just in case... */ + switch (mode) { + case 'N': /* None */ + case 'U': /* Unbuffered */ + mode = _IONBF; + break; + case 'L': /* Line */ + mode = _IOLBF; + break; + case 'B': /* Block */ + case 'F': /* Full */ + mode = _IOFBF; + break; + default: + snprintf(err_buf, sizeof err_buf, + "Invalid --outbuf setting -- specify N, L, or B.\n"); + return 0; + } + setvbuf(stdout, (char *)NULL, mode, 0); + } + + if (msgs2stderr) { + /* Make stderr line buffered for better sharing of the stream. */ + fflush(stderr); /* Just in case... */ + setvbuf(stderr, (char *)NULL, _IOLBF, 0); + } +#endif + set_output_verbosity(verbose, DEFAULT_PRIORITY); if (do_stats) { @@ -1827,15 +1923,6 @@ int parse_arguments(int *argc_p, const char ***argv_p) verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY); } - if (human_readable) { - char buf[32]; - snprintf(buf, sizeof buf, "%f", 3.14); - if (strchr(buf, '.') != NULL) - number_separator = ','; - else - number_separator = '.'; - } - #ifdef ICONV_OPTION if (iconv_opt && protect_args != 2) { if (!am_server && strcmp(iconv_opt, "-") == 0) @@ -1852,6 +1939,10 @@ int parse_arguments(int *argc_p, const char ***argv_p) if (fuzzy_basis > 1) fuzzy_basis = basis_dir_cnt + 1; + /* Don't let the client reset protect_args if it was already processed */ + if (orig_protect_args == 2 && am_server) + protect_args = orig_protect_args; + if (protect_args == 1 && am_server) return 1; @@ -1890,6 +1981,12 @@ int parse_arguments(int *argc_p, const char ***argv_p) } #endif + if (block_size > MAX_BLOCK_SIZE) { + snprintf(err_buf, sizeof err_buf, + "--block-size=%lu is too large (max: %u)\n", block_size, MAX_BLOCK_SIZE); + return 0; + } + if (write_batch && read_batch) { snprintf(err_buf, sizeof err_buf, "--write-batch and --read-batch can not be used together\n"); @@ -2168,14 +2265,6 @@ int parse_arguments(int *argc_p, const char ***argv_p) bwlimit_writemax = 512; } - if (sparse_files && inplace) { - /* Note: we don't check for this below, because --append is - * OK with --sparse (as long as redos are handled right). */ - snprintf(err_buf, sizeof err_buf, - "--sparse cannot be used with --inplace\n"); - return 0; - } - if (append_mode) { if (whole_file > 0) { snprintf(err_buf, sizeof err_buf, @@ -2412,16 +2501,20 @@ void server_options(char **args, int *argc_p) } if (sparse_files) argstr[x++] = 'S'; - if (do_compression) + if (do_compression == 1) argstr[x++] = 'z'; set_allow_inc_recurse(); - /* Checking the pre-negotiated value allows --protocol=29 override. */ + /* We don't really know the actual protocol_version at this point, + * but checking the pre-negotiated value allows the user to use a + * --protocol=29 override to avoid the use of this -eFLAGS opt. */ if (protocol_version >= 30) { + /* Use "eFlags" alias so that cull_options doesn't think that these are no-arg option letters. */ +#define eFlags argstr /* We make use of the -e option to let the server know about * any pre-release protocol version && some behavior flags. */ - argstr[x++] = 'e'; + eFlags[x++] = 'e'; #if SUBPROTOCOL_VERSION != 0 if (protocol_version == PROTOCOL_VERSION) { x += snprintf(argstr+x, sizeof argstr - x, @@ -2429,15 +2522,19 @@ void server_options(char **args, int *argc_p) PROTOCOL_VERSION, SUBPROTOCOL_VERSION); } else #endif - argstr[x++] = '.'; + eFlags[x++] = '.'; if (allow_inc_recurse) - argstr[x++] = 'i'; + eFlags[x++] = 'i'; #ifdef CAN_SET_SYMLINK_TIMES - argstr[x++] = 'L'; + eFlags[x++] = 'L'; /* symlink time-setting support */ #endif #ifdef ICONV_OPTION - argstr[x++] = 's'; + eFlags[x++] = 's'; /* symlink iconv translation support */ #endif + eFlags[x++] = 'f'; /* flist I/O-error safety support */ + eFlags[x++] = 'x'; /* xattr hardlink optimization not desired */ + eFlags[x++] = 'C'; /* support checksum seed order fix */ +#undef eFlags } if (x >= (int)sizeof argstr) { /* Not possible... */ @@ -2532,6 +2629,12 @@ void server_options(char **args, int *argc_p) args[ac++] = arg; } + if (checksum_choice) { + if (asprintf(&arg, "--checksum-choice=%s", checksum_choice) < 0) + goto oom; + args[ac++] = arg; + } + if (am_sender) { if (max_delete > 0) { if (asprintf(&arg, "--max-delete=%d", max_delete) < 0) @@ -2539,11 +2642,11 @@ void server_options(char **args, int *argc_p) args[ac++] = arg; } else if (max_delete == 0) args[ac++] = "--max-delete=-1"; - if (min_size) { + if (min_size >= 0) { args[ac++] = "--min-size"; args[ac++] = min_size_arg; } - if (max_size) { + if (max_size >= 0) { args[ac++] = "--max-size"; args[ac++] = max_size_arg; } @@ -2584,8 +2687,9 @@ void server_options(char **args, int *argc_p) else if (missing_args == 1 && !am_sender) args[ac++] = "--ignore-missing-args"; - if (modify_window_set) { - if (asprintf(&arg, "--modify-window=%d", modify_window) < 0) + if (modify_window_set && am_sender) { + char *fmt = modify_window < 0 ? "-@%d" : "--modify-window=%d"; + if (asprintf(&arg, fmt, modify_window) < 0) goto oom; args[ac++] = arg; } @@ -2705,6 +2809,9 @@ void server_options(char **args, int *argc_p) exit_cleanup(RERR_MALLOC); } + if (do_compression > 1) + args[ac++] = "--new-compress"; + if (remote_option_cnt) { int j; if (ac + remote_option_cnt > MAX_SERVER_ARGS) {