/* * Command-line (and received via daemon-socket) option parsing. * * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> * Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org> * Copyright (C) 2002-2023 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 * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, visit the http://fsf.org website. */ #include "rsync.h"#include "itypes.h"#include "ifuncs.h"#include <popt.h> extern int module_id;extern int local_server;extern int sanitize_paths;extern int operator_path_resolve;extern int trust_sender_args;extern int trust_sender_filter;extern unsigned int module_dirlen;extern filter_rule_list filter_list;extern filter_rule_list daemon_filter_list; int make_backups = 0; /** * If 1, send the whole file as literal data rather than trying to * create an incremental diff. * * If -1, then look at whether we're local or remote and go by that. * * @sa disable_deltas_p() **/int whole_file = -1; int append_mode = 0;int keep_dirlinks = 0;int copy_dirlinks = 0;int copy_links = 0;int copy_devices = 0;int write_devices = 0;int preserve_links = 0;int preserve_hard_links = 0;int preserve_acls = 0;int preserve_xattrs = 0;int preserve_perms = 0;int preserve_executability = 0;int preserve_devices = 0;int preserve_specials = 0;int drop_devices = 0;char *confine_root = NULL; /* --confine-root: see syscall.c */unsigned int confine_rootlen = 0;int preserve_uid = 0;int preserve_gid = 0;int preserve_mtimes = 0;int preserve_atimes = 0;int preserve_crtimes = 0;int omit_dir_times = 0;int omit_link_times = 0;int trust_sender = 0;int update_only = 0;int open_noatime = 0;int cvs_exclude = 0;int dry_run = 0;int do_xfers = 1;int do_fsync = 0;int ignore_times = 0;int delete_mode = 0;int delete_during = 0;int delete_before = 0;int delete_after = 0;int delete_excluded = 0;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 do_compression_level = CLVL_NOT_SPECIFIED;int do_compression_threads = 0; /*n = 0 use rsync thread, n >= 1 spawn n threads for compression */#define MAX_DAEMON_COMPRESSION_THREADS 8int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */int am_server = 0;int am_sender = 0;int am_starting_up = 1;int relative_paths = -1;int implied_dirs = 1;int missing_args = 0; /* 0 = FERROR_XFER, 1 = ignore, 2 = delete */int numeric_ids = 0;int msgs2stderr = 2; /* Default: send errors to stderr for local & remote-shell transfers */int saw_stderr_opt = 0;int allow_8bit_chars = 0;int force_delete = 0;int io_timeout = 0;int prune_empty_dirs = 0;int use_qsort = 0;char *files_from = NULL;int filesfrom_fd = -1;char *filesfrom_host = NULL;int eol_nulls = 0;int protect_args = -1;int old_style_args = -1;int human_readable = 1;int recurse = 0;int mkpath_dest_arg = 0;int allow_inc_recurse = 1;int xfer_dirs = -1;int am_daemon = 0;/* Set after a successful per-module chroot ("use chroot = yes") in * clientserver.c. NOT set for the daemon-level "daemon chroot = /X" * chroot: that confines path resolution to /X, but module paths * /X/modA, /X/modB, etc. are not chroot boundaries, so the per-module * symlink-race defenses (secure_relative_open() / do_*_at() in * syscall.c, gated by `am_daemon && !am_chrooted`) must still fire * even when the daemon is inside a daemon chroot. */int am_chrooted = 0;int connect_timeout = 0;int keep_partial = 0;int safe_symlinks = 0;int copy_unsafe_links = 0;int insecure_links = 0;int munge_symlinks = 0;int use_secure_symlinks = 0;int size_only = 0;int daemon_bwlimit = 0;int bwlimit = 0;int fuzzy_basis = 0;size_t bwlimit_writemax = 0;int ignore_existing = 0;int ignore_non_existing = 0;int need_messages_from_generator = 0;int max_delete = INT_MIN;OFF_T max_size = -1;OFF_T min_size = -1;int ignore_errors = 0;int modify_window = 0;int blocking_io = -1;int checksum_seed = 0;int inplace = 0;int delay_updates = 0;int32 block_size = 0;time_t stop_at_utime = 0;char *skip_compress = NULL;char *copy_as = NULL;item_list dparam_list = EMPTY_ITEM_LIST; /** Network address family. **/int default_af_hint#ifdef INET6 = 0; /* Any protocol */#else = AF_INET; /* Must use IPv4 */# ifdef AF_INET6# undef AF_INET6# endif# define AF_INET6 AF_INET /* make -6 option a no-op */#endif /** Do not go into the background when run as --daemon. Good * for debugging and required for running as a service on W32, * or under Unix process-monitors. **/int no_detach#if defined _WIN32 || defined __WIN32__ = 1;#else = 0;#endif int write_batch = 0;int read_batch = 0;int backup_dir_len = 0;int backup_suffix_len;unsigned int backup_dir_remainder; char *backup_suffix = NULL;char *tmpdir = NULL;char *partial_dir = NULL;char *basis_dir[MAX_BASIS_DIRS+1];char *config_file = NULL;char *shell_cmd = NULL;char *logfile_name = NULL;char *logfile_format = NULL;char *stdout_format = NULL;char *password_file = NULL;char *early_input_file = NULL;char *rsync_path = RSYNC_PATH;char *backup_dir = NULL;char backup_dir_buf[MAXPATHLEN];char *sockopts = NULL;char *usermap = NULL;char *groupmap = NULL;int rsync_port = 0;int alt_dest_type = 0;int basis_dir_cnt = 0; #define DEFAULT_MAX_ALLOC (1024L * 1024 * 1024)size_t max_alloc = DEFAULT_MAX_ALLOC;char *max_alloc_arg; static int version_opt_cnt = 0;static int remote_option_alloc = 0;int remote_option_cnt = 0;const char **remote_options = NULL;const char *checksum_choice = NULL;const char *compress_choice = NULL;static const char *empty_argv[1]; int quiet = 0;int output_motd = 1;int log_before_transfer = 0;int stdout_format_has_i = 0;int stdout_format_has_o_or_i = 0;int logfile_format_has_i = 0;int logfile_format_has_o_or_i = 0;int always_checksum = 0;int list_only = 0; #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */char *batch_name = NULL; int need_unsorted_flist = 0;char *iconv_opt =#ifdef ICONV_OPTION ICONV_OPTION;#else NULL;#endif struct chmod_mode_struct *chmod_modes = NULL; static const char *const debug_verbosity[] = { /*0*/ NULL, /*1*/ NULL, /*2*/ "BIND,CMD,CONNECT,DEL,DELTASUM,DUP,FILTER,FLIST,ICONV", /*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",}; #define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1) static const char *const info_verbosity[1+MAX_VERBOSITY] = { /*0*/ "NONREG", /*1*/ "COPY,DEL,FLIST,MISC,NAME,STATS,SYMSAFE", /*2*/ "BACKUP,MISC2,MOUNT,NAME2,REMOVE,SKIP",}; #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */ short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; #define DEFAULT_PRIORITY 0 /* Default/implied/--verbose set values. */#define HELP_PRIORITY 1 /* The help output uses this level. */#define USER_PRIORITY 2 /* User-specified via --info or --debug */#define LIMIT_PRIORITY 3 /* Overriding priority when limiting values. */ #define W_CLI (1<<0) /* client side */#define W_SRV (1<<1) /* server side */#define W_SND (1<<2) /* sending side */#define W_REC (1<<3) /* receiving side */ struct output_struct { char *name; /* The name of the info/debug flag. */ char *help; /* The description of the info/debug flag. */ uchar namelen; /* The length of the name string. */ uchar flag; /* The flag's value, for consistency check. */ uchar where; /* Bits indicating where the flag is used. */ uchar priority; /* See *_PRIORITY defines. */}; #define INFO_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, INFO_##flag, where, 0 } static struct output_struct info_words[COUNT_INFO+1] = { INFO_WORD(BACKUP, W_REC, "Mention files backed up"), 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 (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(NONREG, W_REC, "Mention skipped non-regular files (default 1, 0 disables)"), INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"), INFO_WORD(REMOVE, W_SND, "Mention files removed on the sending side"), INFO_WORD(SKIP, W_REC, "Mention files skipped due to transfer overrides (levels 1-2)"), INFO_WORD(STATS, W_CLI|W_SRV, "Mention statistics at end of run (levels 1-3)"), INFO_WORD(SYMSAFE, W_SND|W_REC, "Mention symlinks that are unsafe"), { NULL, "--info", 0, 0, 0, 0 }}; #define DEBUG_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, DEBUG_##flag, where, 0 } static struct output_struct debug_words[COUNT_DEBUG+1] = { DEBUG_WORD(ACL, W_SND|W_REC, "Debug extra ACL info"), 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 (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-3)"), DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-3)"), 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 (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(NSTR, W_CLI|W_SRV, "Debug negotiation strings"), 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"), DEBUG_WORD(SEND, W_SND, "Debug sender functions"), DEBUG_WORD(TIME, W_REC, "Debug setting of modified times (levels 1-2)"), { NULL, "--debug", 0, 0, 0, 0 }}; static int verbose = 0;static int do_stats = 0;static int do_progress = 0;static int daemon_opt; /* sets am_daemon after option error-reporting */static int F_option_cnt = 0;static int modify_window_set;static int itemize_changes = 0;static int refused_delete, refused_archive_part, refused_compress;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 *outbuf_mode;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 * interpreted by the IPv6 layer: should be a numeric IP4 or IP6 * address, or a hostname. **/char *bind_address; static void output_item_help(struct output_struct *words); /* This constructs a string that represents all the options set for either * the --info or --debug setting, skipping any implied options (by -v, etc.). * This is used both when conveying the user's options to the server, and * when the help output wants to tell the user what options are implied. */static char *make_output_option(struct output_struct *words, short *levels, uchar where){ char *str = words == info_words ? "--info=" : "--debug="; int j, counts[MAX_OUT_LEVEL+1], pos, skipped = 0, len = 0, max = 0, lev = 0; int word_count = words == info_words ? COUNT_INFO : COUNT_DEBUG; char *buf; memset(counts, 0, sizeof counts); for (j = 0; words[j].name; j++) { if (words[j].flag != j) { rprintf(FERROR, "rsync: internal error on %s%s: %d != %d\n", words == info_words ? "INFO_" : "DEBUG_", words[j].name, words[j].flag, j); exit_cleanup(RERR_UNSUPPORTED); } if (!(words[j].where & where)) continue; if (words[j].priority == DEFAULT_PRIORITY) { /* Implied items don't need to be mentioned. */ skipped++; continue; } len += len ? 1 : strlen(str); len += strlen(words[j].name); len += levels[j] == 1 ? 0 : 1; if (words[j].priority == HELP_PRIORITY) continue; /* no abbreviating for help */ assert(levels[j] <= MAX_OUT_LEVEL); if (++counts[levels[j]] > max) { /* Determine which level has the most items. */ lev = levels[j]; max = counts[lev]; } } /* Sanity check the COUNT_* define against the length of the table. */ if (j != word_count) { rprintf(FERROR, "rsync: internal error: %s is wrong! (%d != %d)\n", words == info_words ? "COUNT_INFO" : "COUNT_DEBUG", j, word_count); exit_cleanup(RERR_UNSUPPORTED); } if (!len) return NULL; len++; buf = new_array(char, len); pos = 0; if (skipped || max < 5) lev = -1; else { if (lev == 0) pos += snprintf(buf, len, "%sNONE", str); else if (lev == 1) pos += snprintf(buf, len, "%sALL", str); else pos += snprintf(buf, len, "%sALL%d", str, lev); } for (j = 0; words[j].name && pos < len; j++) { if (words[j].priority == DEFAULT_PRIORITY || levels[j] == lev || !(words[j].where & where)) continue; if (pos) buf[pos++] = ','; else pos += strlcpy(buf+pos, str, len-pos); if (pos < len) pos += strlcpy(buf+pos, words[j].name, len-pos); /* Level 1 is implied by the name alone. */ if (levels[j] != 1 && pos < len) buf[pos++] = '0' + levels[j]; } buf[pos] = '\0'; return buf;} static void parse_output_words(struct output_struct *words, short *levels, const char *str, uchar priority){ const char *s; int j, len, lev; for ( ; str; str = s) { if ((s = strchr(str, ',')) != NULL) len = s++ - str; else len = strlen(str); if (!len) continue; if (!isDigit(str)) { while (len && isDigit(str+len-1)) len--; } lev = isDigit(str+len) ? atoi(str+len) : 1; /* atoi() of an overflowing positive digit string can return a * negative int (LONG_MAX truncated on LP64); a negative lev * here later indexes counts[lev] in make_output_option(). */ if (lev > MAX_OUT_LEVEL || lev < 0) lev = MAX_OUT_LEVEL; if (len == 4 && strncasecmp(str, "help", 4) == 0) { output_item_help(words); exit_cleanup(0); } if (len == 4 && strncasecmp(str, "none", 4) == 0) len = lev = 0; else if (len == 3 && strncasecmp(str, "all", 3) == 0) len = 0; for (j = 0; words[j].name; j++) { if (!len || (len == words[j].namelen && strncasecmp(str, words[j].name, len) == 0)) { if (priority >= words[j].priority) { words[j].priority = priority; levels[j] = lev; } if (len) break; } } if (len && !words[j].name && !am_server) { rprintf(FERROR, "Unknown %s item: \"%.*s\"\n", words[j].help, len, str); exit_cleanup(RERR_SYNTAX); } }} /* Tell the user what all the info or debug flags mean. */static void output_item_help(struct output_struct *words){ short *levels = words == info_words ? info_levels : debug_levels; const char *const*verbosity = words == info_words ? info_verbosity : debug_verbosity; char buf[128], *opt, *fmt = "%-10s %s\n"; int j; reset_output_levels();Lines 1–500 of 3336. Load more
/* * Command-line (and received via daemon-socket) option parsing. * * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org> * Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org> * Copyright (C) 2002-2023 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 * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, visit the http://fsf.org website. */ #include "rsync.h" #include "itypes.h" #include "ifuncs.h" #include <popt.h> extern int module_id; extern int local_server; extern int sanitize_paths; extern int operator_path_resolve; extern int trust_sender_args; extern int trust_sender_filter; extern unsigned int module_dirlen; extern filter_rule_list filter_list; extern filter_rule_list daemon_filter_list; int make_backups = 0; /** * If 1, send the whole file as literal data rather than trying to * create an incremental diff. * * If -1, then look at whether we're local or remote and go by that. * * @sa disable_deltas_p() **/ int whole_file = -1; int append_mode = 0; int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; int copy_devices = 0; int write_devices = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; int preserve_xattrs = 0; int preserve_perms = 0; int preserve_executability = 0; int preserve_devices = 0; int preserve_specials = 0; int drop_devices = 0; char *confine_root = NULL; /* --confine-root: see syscall.c */ unsigned int confine_rootlen = 0; int preserve_uid = 0; int preserve_gid = 0; int preserve_mtimes = 0; int preserve_atimes = 0; int preserve_crtimes = 0; int omit_dir_times = 0; int omit_link_times = 0; int trust_sender = 0; int update_only = 0; int open_noatime = 0; int cvs_exclude = 0; int dry_run = 0; int do_xfers = 1; int do_fsync = 0; int ignore_times = 0; int delete_mode = 0; int delete_during = 0; int delete_before = 0; int delete_after = 0; int delete_excluded = 0; 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 do_compression_level = CLVL_NOT_SPECIFIED; int do_compression_threads = 0; /*n = 0 use rsync thread, n >= 1 spawn n threads for compression */ #define MAX_DAEMON_COMPRESSION_THREADS 8 int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */ int am_server = 0; int am_sender = 0; int am_starting_up = 1; int relative_paths = -1; int implied_dirs = 1; int missing_args = 0; /* 0 = FERROR_XFER, 1 = ignore, 2 = delete */ int numeric_ids = 0; int msgs2stderr = 2; /* Default: send errors to stderr for local & remote-shell transfers */ int saw_stderr_opt = 0; int allow_8bit_chars = 0; int force_delete = 0; int io_timeout = 0; int prune_empty_dirs = 0; int use_qsort = 0; char *files_from = NULL; int filesfrom_fd = -1; char *filesfrom_host = NULL; int eol_nulls = 0; int protect_args = -1; int old_style_args = -1; int human_readable = 1; int recurse = 0; int mkpath_dest_arg = 0; int allow_inc_recurse = 1; int xfer_dirs = -1; int am_daemon = 0; /* Set after a successful per-module chroot ("use chroot = yes") in * clientserver.c. NOT set for the daemon-level "daemon chroot = /X" * chroot: that confines path resolution to /X, but module paths * /X/modA, /X/modB, etc. are not chroot boundaries, so the per-module * symlink-race defenses (secure_relative_open() / do_*_at() in * syscall.c, gated by `am_daemon && !am_chrooted`) must still fire * even when the daemon is inside a daemon chroot. */ int am_chrooted = 0; int connect_timeout = 0; int keep_partial = 0; int safe_symlinks = 0; int copy_unsafe_links = 0; int insecure_links = 0; int munge_symlinks = 0; int use_secure_symlinks = 0; int size_only = 0; int daemon_bwlimit = 0; int bwlimit = 0; int fuzzy_basis = 0; size_t bwlimit_writemax = 0; int ignore_existing = 0; int ignore_non_existing = 0; int need_messages_from_generator = 0; int max_delete = INT_MIN; OFF_T max_size = -1; OFF_T min_size = -1; int ignore_errors = 0; int modify_window = 0; int blocking_io = -1; int checksum_seed = 0; int inplace = 0; int delay_updates = 0; int32 block_size = 0; time_t stop_at_utime = 0; char *skip_compress = NULL; char *copy_as = NULL; item_list dparam_list = EMPTY_ITEM_LIST; /** Network address family. **/ int default_af_hint #ifdef INET6 = 0; /* Any protocol */ #else = AF_INET; /* Must use IPv4 */ # ifdef AF_INET6 # undef AF_INET6 # endif # define AF_INET6 AF_INET /* make -6 option a no-op */ #endif /** Do not go into the background when run as --daemon. Good * for debugging and required for running as a service on W32, * or under Unix process-monitors. **/ int no_detach #if defined _WIN32 || defined __WIN32__ = 1; #else = 0; #endif int write_batch = 0; int read_batch = 0; int backup_dir_len = 0; int backup_suffix_len; unsigned int backup_dir_remainder; char *backup_suffix = NULL; char *tmpdir = NULL; char *partial_dir = NULL; char *basis_dir[MAX_BASIS_DIRS+1]; char *config_file = NULL; char *shell_cmd = NULL; char *logfile_name = NULL; char *logfile_format = NULL; char *stdout_format = NULL; char *password_file = NULL; char *early_input_file = NULL; char *rsync_path = RSYNC_PATH; char *backup_dir = NULL; char backup_dir_buf[MAXPATHLEN]; char *sockopts = NULL; char *usermap = NULL; char *groupmap = NULL; int rsync_port = 0; int alt_dest_type = 0; int basis_dir_cnt = 0; #define DEFAULT_MAX_ALLOC (1024L * 1024 * 1024) size_t max_alloc = DEFAULT_MAX_ALLOC; char *max_alloc_arg; static int version_opt_cnt = 0; static int remote_option_alloc = 0; int remote_option_cnt = 0; const char **remote_options = NULL; const char *checksum_choice = NULL; const char *compress_choice = NULL; static const char *empty_argv[1]; int quiet = 0; int output_motd = 1; int log_before_transfer = 0; int stdout_format_has_i = 0; int stdout_format_has_o_or_i = 0; int logfile_format_has_i = 0; int logfile_format_has_o_or_i = 0; int always_checksum = 0; int list_only = 0; #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */ char *batch_name = NULL; int need_unsorted_flist = 0; char *iconv_opt = #ifdef ICONV_OPTION ICONV_OPTION; #else NULL; #endif struct chmod_mode_struct *chmod_modes = NULL; static const char *const debug_verbosity[] = { /*0*/ NULL, /*1*/ NULL, /*2*/ "BIND,CMD,CONNECT,DEL,DELTASUM,DUP,FILTER,FLIST,ICONV", /*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", }; #define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1) static const char *const info_verbosity[1+MAX_VERBOSITY] = { /*0*/ "NONREG", /*1*/ "COPY,DEL,FLIST,MISC,NAME,STATS,SYMSAFE", /*2*/ "BACKUP,MISC2,MOUNT,NAME2,REMOVE,SKIP", }; #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */ short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; #define DEFAULT_PRIORITY 0 /* Default/implied/--verbose set values. */ #define HELP_PRIORITY 1 /* The help output uses this level. */ #define USER_PRIORITY 2 /* User-specified via --info or --debug */ #define LIMIT_PRIORITY 3 /* Overriding priority when limiting values. */ #define W_CLI (1<<0) /* client side */ #define W_SRV (1<<1) /* server side */ #define W_SND (1<<2) /* sending side */ #define W_REC (1<<3) /* receiving side */ struct output_struct { char *name; /* The name of the info/debug flag. */ char *help; /* The description of the info/debug flag. */ uchar namelen; /* The length of the name string. */ uchar flag; /* The flag's value, for consistency check. */ uchar where; /* Bits indicating where the flag is used. */ uchar priority; /* See *_PRIORITY defines. */ }; #define INFO_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, INFO_##flag, where, 0 } static struct output_struct info_words[COUNT_INFO+1] = { INFO_WORD(BACKUP, W_REC, "Mention files backed up"), 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 (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(NONREG, W_REC, "Mention skipped non-regular files (default 1, 0 disables)"), INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"), INFO_WORD(REMOVE, W_SND, "Mention files removed on the sending side"), INFO_WORD(SKIP, W_REC, "Mention files skipped due to transfer overrides (levels 1-2)"), INFO_WORD(STATS, W_CLI|W_SRV, "Mention statistics at end of run (levels 1-3)"), INFO_WORD(SYMSAFE, W_SND|W_REC, "Mention symlinks that are unsafe"), { NULL, "--info", 0, 0, 0, 0 } }; #define DEBUG_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, DEBUG_##flag, where, 0 } static struct output_struct debug_words[COUNT_DEBUG+1] = { DEBUG_WORD(ACL, W_SND|W_REC, "Debug extra ACL info"), 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 (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-3)"), DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-3)"), 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 (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(NSTR, W_CLI|W_SRV, "Debug negotiation strings"), 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"), DEBUG_WORD(SEND, W_SND, "Debug sender functions"), DEBUG_WORD(TIME, W_REC, "Debug setting of modified times (levels 1-2)"), { NULL, "--debug", 0, 0, 0, 0 } }; static int verbose = 0; static int do_stats = 0; static int do_progress = 0; static int daemon_opt; /* sets am_daemon after option error-reporting */ static int F_option_cnt = 0; static int modify_window_set; static int itemize_changes = 0; static int refused_delete, refused_archive_part, refused_compress; 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 *outbuf_mode; 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 * interpreted by the IPv6 layer: should be a numeric IP4 or IP6 * address, or a hostname. **/ char *bind_address; static void output_item_help(struct output_struct *words); /* This constructs a string that represents all the options set for either * the --info or --debug setting, skipping any implied options (by -v, etc.). * This is used both when conveying the user's options to the server, and * when the help output wants to tell the user what options are implied. */ static char *make_output_option(struct output_struct *words, short *levels, uchar where) { char *str = words == info_words ? "--info=" : "--debug="; int j, counts[MAX_OUT_LEVEL+1], pos, skipped = 0, len = 0, max = 0, lev = 0; int word_count = words == info_words ? COUNT_INFO : COUNT_DEBUG; char *buf; memset(counts, 0, sizeof counts); for (j = 0; words[j].name; j++) { if (words[j].flag != j) { rprintf(FERROR, "rsync: internal error on %s%s: %d != %d\n", words == info_words ? "INFO_" : "DEBUG_", words[j].name, words[j].flag, j); exit_cleanup(RERR_UNSUPPORTED); } if (!(words[j].where & where)) continue; if (words[j].priority == DEFAULT_PRIORITY) { /* Implied items don't need to be mentioned. */ skipped++; continue; } len += len ? 1 : strlen(str); len += strlen(words[j].name); len += levels[j] == 1 ? 0 : 1; if (words[j].priority == HELP_PRIORITY) continue; /* no abbreviating for help */ assert(levels[j] <= MAX_OUT_LEVEL); if (++counts[levels[j]] > max) { /* Determine which level has the most items. */ lev = levels[j]; max = counts[lev]; } } /* Sanity check the COUNT_* define against the length of the table. */ if (j != word_count) { rprintf(FERROR, "rsync: internal error: %s is wrong! (%d != %d)\n", words == info_words ? "COUNT_INFO" : "COUNT_DEBUG", j, word_count); exit_cleanup(RERR_UNSUPPORTED); } if (!len) return NULL; len++; buf = new_array(char, len); pos = 0; if (skipped || max < 5) lev = -1; else { if (lev == 0) pos += snprintf(buf, len, "%sNONE", str); else if (lev == 1) pos += snprintf(buf, len, "%sALL", str); else pos += snprintf(buf, len, "%sALL%d", str, lev); } for (j = 0; words[j].name && pos < len; j++) { if (words[j].priority == DEFAULT_PRIORITY || levels[j] == lev || !(words[j].where & where)) continue; if (pos) buf[pos++] = ','; else pos += strlcpy(buf+pos, str, len-pos); if (pos < len) pos += strlcpy(buf+pos, words[j].name, len-pos); /* Level 1 is implied by the name alone. */ if (levels[j] != 1 && pos < len) buf[pos++] = '0' + levels[j]; } buf[pos] = '\0'; return buf; } static void parse_output_words(struct output_struct *words, short *levels, const char *str, uchar priority) { const char *s; int j, len, lev; for ( ; str; str = s) { if ((s = strchr(str, ',')) != NULL) len = s++ - str; else len = strlen(str); if (!len) continue; if (!isDigit(str)) { while (len && isDigit(str+len-1)) len--; } lev = isDigit(str+len) ? atoi(str+len) : 1; /* atoi() of an overflowing positive digit string can return a * negative int (LONG_MAX truncated on LP64); a negative lev * here later indexes counts[lev] in make_output_option(). */ if (lev > MAX_OUT_LEVEL || lev < 0) lev = MAX_OUT_LEVEL; if (len == 4 && strncasecmp(str, "help", 4) == 0) { output_item_help(words); exit_cleanup(0); } if (len == 4 && strncasecmp(str, "none", 4) == 0) len = lev = 0; else if (len == 3 && strncasecmp(str, "all", 3) == 0) len = 0; for (j = 0; words[j].name; j++) { if (!len || (len == words[j].namelen && strncasecmp(str, words[j].name, len) == 0)) { if (priority >= words[j].priority) { words[j].priority = priority; levels[j] = lev; } if (len) break; } } if (len && !words[j].name && !am_server) { rprintf(FERROR, "Unknown %s item: \"%.*s\"\n", words[j].help, len, str); exit_cleanup(RERR_SYNTAX); } } } /* Tell the user what all the info or debug flags mean. */ static void output_item_help(struct output_struct *words) { short *levels = words == info_words ? info_levels : debug_levels; const char *const*verbosity = words == info_words ? info_verbosity : debug_verbosity; char buf[128], *opt, *fmt = "%-10s %s\n"; int j; reset_output_levels();