X-Git-Url: http://git.samba.org/samba.git/?p=rsync.git;a=blobdiff_plain;f=options.c;h=e5b0cb68280ed5e1d5cfea93e314c1c67c74ebe9;hp=bd6a495d9ec08ba3d74d76d8502941c6a1cdd771;hb=3e2e4b5a33c72ef428ff40989a1ba03b4d24c9fb;hpb=7b6c5c77942b8d11631c873b008e0b405d435bc0 diff --git a/options.c b/options.c index bd6a495d..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-2009 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 @@ -22,7 +22,7 @@ #include "rsync.h" #include "itypes.h" #include -#include "zlib/zlib.h" +#include extern int module_id; extern int local_server; @@ -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; /** @@ -73,8 +75,9 @@ int remove_source_files = 0; int one_file_system = 0; 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; @@ -93,7 +96,7 @@ char *files_from = NULL; int filesfrom_fd = -1; char *filesfrom_host = NULL; int eol_nulls = 0; -int protect_args = 0; +int protect_args = -1; int human_readable = 1; int recurse = 0; int allow_inc_recurse = 1; @@ -113,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; @@ -122,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; @@ -180,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; @@ -205,7 +208,7 @@ static const char *debug_verbosity[] = { /*0*/ NULL, /*1*/ NULL, /*2*/ "BIND,CMD,CONNECT,DEL,DELTASUM,DUP,FILTER,FLIST,ICONV", - /*3*/ "ACL,BACKUP,DELTASUM2,DEL2,EXIT,FILTER2,FLIST2,FUZZY,GENR,OWN,RECV,SEND,TIME", + /*3*/ "ACL,BACKUP,CONNECT2,DELTASUM2,DEL2,EXIT,FILTER2,FLIST2,FUZZY,GENR,OWN,RECV,SEND,TIME", /*4*/ "CMD2,DELTASUM3,DEL3,EXIT2,FLIST3,ICONV2,OWN2,PROTO,TIME2", /*5*/ "CHDIR,DELTASUM4,FLIST4,FUZZY2,HASH,HLINK", }; @@ -215,7 +218,7 @@ static const char *debug_verbosity[] = { static const char *info_verbosity[1+MAX_VERBOSITY] = { /*0*/ NULL, /*1*/ "COPY,DEL,FLIST,MISC,NAME,STATS,SYMSAFE", - /*2*/ "BACKUP,MOUNT,NAME2,REMOVE,SKIP", + /*2*/ "BACKUP,MISC2,MOUNT,NAME2,REMOVE,SKIP", }; #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */ @@ -248,7 +251,7 @@ static struct output_struct info_words[COUNT_INFO+1] = { INFO_WORD(COPY, W_REC, "Mention files copied locally on the receiving side"), INFO_WORD(DEL, W_REC, "Mention deletions on the receiving side"), INFO_WORD(FLIST, W_CLI, "Mention file-list receiving/sending (levels 1-2)"), - INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information"), + INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information (levels 1-2)"), INFO_WORD(MOUNT, W_SND|W_REC, "Mention mounts that were found or skipped"), INFO_WORD(NAME, W_SND|W_REC, "Mention 1) updated file/dir names, 2) unchanged names"), INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"), @@ -266,19 +269,20 @@ static struct output_struct debug_words[COUNT_DEBUG+1] = { DEBUG_WORD(BACKUP, W_REC, "Debug backup actions (levels 1-2)"), DEBUG_WORD(BIND, W_CLI, "Debug socket bind actions"), DEBUG_WORD(CHDIR, W_CLI|W_SRV, "Debug when the current directory changes"), - DEBUG_WORD(CONNECT, W_CLI, "Debug connection events"), + DEBUG_WORD(CONNECT, W_CLI, "Debug connection events (levels 1-2)"), DEBUG_WORD(CMD, W_CLI, "Debug commands+options that are issued (levels 1-2)"), DEBUG_WORD(DEL, W_REC, "Debug delete actions (levels 1-3)"), DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"), DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"), - DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-2)"), + DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"), DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"), DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"), DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"), DEBUG_WORD(GENR, W_REC, "Debug generator functions"), DEBUG_WORD(HASH, W_SND|W_REC, "Debug hashtable code"), - DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions"), + DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions (levels 1-3)"), DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv character conversions (levels 1-2)"), + DEBUG_WORD(IO, W_CLI|W_SRV, "Debug I/O routines (levels 1-4)"), DEBUG_WORD(OWN, W_REC, "Debug ownership changes in users & groups (levels 1-2)"), DEBUG_WORD(PROTO, W_CLI|W_SRV, "Debug protocol information"), DEBUG_WORD(RECV, W_REC, "Debug receiver functions"), @@ -292,6 +296,7 @@ static int do_stats = 0; static int do_progress = 0; static int daemon_opt; /* sets am_daemon after option error-reporting */ static int omit_dir_times = 0; +static int omit_link_times = 0; static int F_option_cnt = 0; static int modify_window_set; static int itemize_changes = 0; @@ -300,7 +305,10 @@ 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; -static char *max_size_arg, *min_size_arg; +#ifdef HAVE_SETVBUF +static char *outbuf_mode; +#endif +static char *bwlimit_arg, *max_size_arg, *min_size_arg; static char tmp_partialdir[] = ".~tmp~"; /** Local address to bind. As a character string because it's @@ -404,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; @@ -441,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; } } @@ -560,6 +566,7 @@ static void print_rsync_version(enum logcode f) char const *got_socketpair = "no "; char const *have_inplace = "no "; char const *hardlinks = "no "; + char const *prealloc = "no "; char const *symtimes = "no "; char const *acls = "no "; char const *xattrs = "no "; @@ -581,6 +588,9 @@ static void print_rsync_version(enum logcode f) #ifdef SUPPORT_HARD_LINKS hardlinks = ""; #endif +#ifdef SUPPORT_PREALLOCATION + prealloc = ""; +#endif #ifdef SUPPORT_ACLS acls = ""; #endif @@ -596,13 +606,13 @@ static void print_rsync_version(enum logcode f) #ifdef ICONV_OPTION iconv = ""; #endif -#if defined HAVE_LUTIMES && defined HAVE_UTIMES +#ifdef CAN_SET_SYMLINK_TIMES symtimes = ""; #endif rprintf(f, "%s version %s protocol version %d%s\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); - rprintf(f, "Copyright (C) 1996-2009 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", @@ -612,8 +622,8 @@ static void print_rsync_version(enum logcode f) (int)(sizeof (int64) * 8)); rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", got_socketpair, hardlinks, links, ipv6, have_inplace); - rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes\n", - have_inplace, acls, xattrs, iconv, symtimes); + rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc\n", + have_inplace, acls, xattrs, iconv, symtimes, prealloc); #ifdef MAINTAINER_MODE rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); @@ -658,6 +668,7 @@ void usage(enum logcode F) rprintf(F," -v, --verbose increase verbosity\n"); rprintf(F," --info=FLAGS fine-grained informational verbosity\n"); rprintf(F," --debug=FLAGS fine-grained debug verbosity\n"); + rprintf(F," --msgs2stderr special output handling for debugging\n"); rprintf(F," -q, --quiet suppress non-error messages\n"); rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n"); rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n"); @@ -698,13 +709,20 @@ void usage(enum logcode F) rprintf(F," -D same as --devices --specials\n"); rprintf(F," -t, --times preserve modification times\n"); rprintf(F," -O, --omit-dir-times omit directories from --times\n"); + rprintf(F," -J, --omit-link-times omit symlinks from --times\n"); rprintf(F," --super receiver attempts super-user activities\n"); #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 + rprintf(F," --preallocate pre-allocate dest files on remote receiver\n"); +#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"); @@ -715,7 +733,7 @@ void usage(enum logcode F) rprintf(F," --del an alias for --delete-during\n"); rprintf(F," --delete delete extraneous files from destination dirs\n"); rprintf(F," --delete-before receiver deletes before transfer, not during\n"); - rprintf(F," --delete-during receiver deletes during transfer (default)\n"); + rprintf(F," --delete-during receiver deletes during the transfer\n"); rprintf(F," --delete-delay find deletions during, delete after\n"); rprintf(F," --delete-after receiver deletes after transfer, not during\n"); rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); @@ -739,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"); @@ -774,7 +792,10 @@ void usage(enum logcode F) rprintf(F," --log-file-format=FMT log updates using the specified FMT\n"); 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=KBPS limit I/O bandwidth; KBytes per second\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"); @@ -782,10 +803,11 @@ 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"); - rprintf(F,"(-h) --help show this help (-h works with no other options)\n"); + rprintf(F,"(-h) --help show this help (-h is --help only if used alone)\n"); rprintf(F,"\n"); rprintf(F,"Use \"rsync --daemon --help\" to see the daemon-mode command-line options.\n"); @@ -798,7 +820,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD, OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE, OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, - OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, + OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_SERVER, OPT_REFUSED_BASE = 9000}; static struct poptOption long_options[] = { @@ -842,13 +864,16 @@ 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, 2, 0, 0 }, + {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 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, 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 }, + {"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", '@', 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 }, @@ -888,8 +913,8 @@ static struct poptOption long_options[] = { {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 }, {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 }, {"one-file-system", 'x', POPT_ARG_NONE, 0, 'x', 0, 0 }, - {"no-one-file-system",'x',POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, - {"no-x", 'x', POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, + {"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, + {"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 }, {"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, {"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, @@ -899,6 +924,7 @@ static struct poptOption long_options[] = { {"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 }, {"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 }, {"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 }, + {"preallocate", 0, POPT_ARG_NONE, &preallocate_files, 0, 0, 0}, {"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 }, {"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 }, {"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 }, @@ -929,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 }, @@ -937,14 +964,16 @@ static struct poptOption long_options[] = { {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 }, {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 }, {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 }, - {"fuzzy", 'y', POPT_ARG_VAL, &fuzzy_basis, 1, 0, 0 }, + {"fuzzy", 'y', POPT_ARG_NONE, 0, 'y', 0, 0 }, {"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 }, @@ -963,7 +992,7 @@ static struct poptOption long_options[] = { {"itemize-changes", 'i', POPT_ARG_NONE, 0, 'i', 0, 0 }, {"no-itemize-changes",0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, {"no-i", 0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, - {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 }, + {"bwlimit", 0, POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 }, {"no-bwlimit", 0, POPT_ARG_VAL, &bwlimit, 0, 0, 0 }, {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 }, {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 }, @@ -1007,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 }, @@ -1028,7 +1060,7 @@ static void daemon_usage(enum logcode F) rprintf(F,"\n"); rprintf(F,"Usage: rsync --daemon [OPTION]...\n"); rprintf(F," --address=ADDRESS bind to the specified address\n"); - rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n"); + rprintf(F," --bwlimit=RATE limit socket I/O bandwidth\n"); rprintf(F," --config=FILE specify alternate rsyncd.conf file\n"); rprintf(F," -M, --dparam=OVERRIDE override global daemon config parameter\n"); rprintf(F," --no-detach do not detach from the parent\n"); @@ -1219,7 +1251,7 @@ static OFF_T parse_size_arg(char **size_arg, char def_suf) size += atoi(arg), make_compatible = 1, arg += 2; if (*arg) return -1; - if (size > 0 && make_compatible) { + if (size > 0 && make_compatible && def_suf == 'b') { /* We convert this manually because we may need %lld precision, * and that's not a portable sprintf() escape. */ char buf[128], *s = buf + sizeof buf - 1; @@ -1249,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. @@ -1265,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) { @@ -1277,7 +1330,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) } #ifdef ICONV_OPTION - if (!am_daemon && !protect_args && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) + if (!am_daemon && protect_args <= 0 && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) iconv_opt = strdup(arg); #endif @@ -1288,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; @@ -1332,6 +1388,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) #ifdef ICONV_OPTION iconv_opt = NULL; #endif + protect_args = 0; poptFreeContext(pc); pc = poptGetContext(RSYNC_NAME, argc, argv, long_daemon_options, 0); @@ -1399,17 +1456,18 @@ int parse_arguments(int *argc_p, const char ***argv_p) break; case OPT_FILTER: - parse_rule(&filter_list, poptGetOptArg(pc), 0, 0); + parse_filter_str(&filter_list, poptGetOptArg(pc), + rule_template(0), 0); break; case OPT_EXCLUDE: - parse_rule(&filter_list, poptGetOptArg(pc), - 0, XFLG_OLD_PREFIXES); + parse_filter_str(&filter_list, poptGetOptArg(pc), + rule_template(0), XFLG_OLD_PREFIXES); break; case OPT_INCLUDE: - parse_rule(&filter_list, poptGetOptArg(pc), - FILTRULE_INCLUDE, XFLG_OLD_PREFIXES); + parse_filter_str(&filter_list, poptGetOptArg(pc), + rule_template(FILTRULE_INCLUDE), XFLG_OLD_PREFIXES); break; case OPT_EXCLUDE_FROM: @@ -1419,20 +1477,22 @@ int parse_arguments(int *argc_p, const char ***argv_p) arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT); if (daemon_filter_list.head) { int rej; - char *dir, *cp = strdup(arg); + char *cp = strdup(arg); if (!cp) out_of_memory("parse_arguments"); if (!*cp) - goto options_rejected; - dir = cp + (*cp == '/' ? module_dirlen : 0); - clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); - rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0; + rej = 1; + else { + char *dir = cp + (*cp == '/' ? module_dirlen : 0); + clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); + rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0; + } free(cp); if (rej) goto options_rejected; } parse_filter_file(&filter_list, arg, - opt == OPT_INCLUDE_FROM ? FILTRULE_INCLUDE : 0, + rule_template(opt == OPT_INCLUDE_FROM ? FILTRULE_INCLUDE : 0), XFLG_FATAL_ERRORS | XFLG_OLD_PREFIXES); break; @@ -1447,7 +1507,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) preserve_links = 1; #endif preserve_perms = 1; - preserve_times = 2; + preserve_times = 1; preserve_gid = 1; preserve_uid = 1; preserve_devices = 1; @@ -1478,6 +1538,10 @@ int parse_arguments(int *argc_p, const char ***argv_p) verbose++; break; + case 'y': + fuzzy_basis++; + break; + case 'q': quiet++; break; @@ -1489,10 +1553,10 @@ int parse_arguments(int *argc_p, const char ***argv_p) case 'F': switch (++F_option_cnt) { case 1: - parse_rule(&filter_list,": /.rsync-filter",0,0); + parse_filter_str(&filter_list,": /.rsync-filter",rule_template(0),0); break; case 2: - parse_rule(&filter_list,"- .rsync-filter",0,0); + parse_filter_str(&filter_list,"- .rsync-filter",rule_template(0),0); break; } break; @@ -1508,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': @@ -1564,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); @@ -1573,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); @@ -1581,6 +1634,23 @@ int parse_arguments(int *argc_p, const char ***argv_p) } break; + case OPT_BWLIMIT: + { + OFF_T limit = parse_size_arg(&bwlimit_arg, 'K'); + if (limit < 0) { + snprintf(err_buf, sizeof err_buf, + "--bwlimit value is invalid: %s\n", bwlimit_arg); + return 0; + } + bwlimit = (limit + 512) / 1024; + if (limit && !bwlimit) { + snprintf(err_buf, sizeof err_buf, + "--bwlimit value is too small: %s\n", bwlimit_arg); + return 0; + } + } + break; + case OPT_APPEND: if (am_server) append_mode++; @@ -1757,12 +1827,95 @@ int parse_arguments(int *argc_p, const char ***argv_p) } } + if (protect_args < 0) { + if (am_server) + protect_args = 0; + else if ((arg = getenv("RSYNC_PROTECT_ARGS")) != NULL && *arg) + protect_args = atoi(arg) ? 1 : 0; + else { +#ifdef RSYNC_USE_PROTECTED_ARGS + protect_args = 1; +#else + protect_args = 0; +#endif + } + } + + 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) { @@ -1770,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) @@ -1792,6 +1936,13 @@ int parse_arguments(int *argc_p, const char ***argv_p) } #endif + 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; @@ -1830,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"); @@ -1895,7 +2052,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) list_only |= 1; if (xfer_dirs >= 4) { - parse_rule(&filter_list, "- /*/*", 0, 0); + parse_filter_str(&filter_list, "- /*/*", rule_template(0), 0); recurse = xfer_dirs = 1; } else if (recurse) xfer_dirs = 1; @@ -1929,7 +2086,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) } if (!xfer_dirs && delete_mode) { snprintf(err_buf, sizeof err_buf, - "--delete does not work without -r or -d.\n"); + "--delete does not work without --recursive (-r) or --dirs (-d).\n"); return 0; } @@ -2003,17 +2160,18 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; } if (backup_dir) { + size_t len; while (*backup_dir == '.' && backup_dir[1] == '/') backup_dir += 2; if (*backup_dir == '.' && backup_dir[1] == '\0') backup_dir++; - backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf); - backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len; - if (backup_dir_remainder < 128) { + len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf); + if (len > sizeof backup_dir_buf - 128) { snprintf(err_buf, sizeof err_buf, "the --backup-dir path is WAY too long.\n"); return 0; } + backup_dir_len = (int)len; if (!backup_dir_len) { backup_dir_len = -1; backup_dir = NULL; @@ -2021,6 +2179,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) backup_dir_buf[backup_dir_len++] = '/'; backup_dir_buf[backup_dir_len] = '\0'; } + backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len; } if (backup_dir) { /* No need for a suffix or a protect rule. */ @@ -2033,16 +2192,22 @@ int parse_arguments(int *argc_p, const char ***argv_p) } 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_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0); + } + + if (preserve_times) { + preserve_times = PRESERVE_FILE_TIMES; + if (!omit_dir_times) + preserve_times |= PRESERVE_DIR_TIMES; +#ifdef CAN_SET_SYMLINK_TIMES + if (!omit_link_times) + preserve_times |= PRESERVE_LINK_TIMES; +#endif } 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; + preserve_times &= ~PRESERVE_DIR_TIMES; } if (stdout_format) { @@ -2100,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, @@ -2168,7 +2325,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) if (files_from) { char *h, *p; int q; - if (argc > 2 || (!am_daemon && argc == 1)) { + if (argc > 2 || (!am_daemon && !am_server && argc == 1)) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } @@ -2279,6 +2436,13 @@ void server_options(char **args, int *argc_p) argstr[x++] = 'm'; if (omit_dir_times) argstr[x++] = 'O'; + if (omit_link_times) + argstr[x++] = 'J'; + if (fuzzy_basis) { + argstr[x++] = 'y'; + if (fuzzy_basis > 1) + argstr[x++] = 'y'; + } } else { if (copy_links) argstr[x++] = 'L'; @@ -2337,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, @@ -2354,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'; -#if defined HAVE_LUTIMES && defined HAVE_UTIMES - argstr[x++] = 'L'; + eFlags[x++] = 'i'; +#ifdef CAN_SET_SYMLINK_TIMES + 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... */ @@ -2457,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) @@ -2464,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; } @@ -2509,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; } @@ -2617,19 +2796,22 @@ void server_options(char **args, int *argc_p) if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30)) args[ac++] = "--no-implied-dirs"; - if (fuzzy_basis && am_sender) - args[ac++] = "--fuzzy"; - if (remove_source_files == 1) args[ac++] = "--remove-source-files"; else if (remove_source_files) args[ac++] = "--remove-sent-files"; + if (preallocate_files && am_sender) + args[ac++] = "--preallocate"; + if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); 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) {