3336 lines · 103.6 KB · C
RawDownload
/* * 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.