1: /*
2: * Command-line (and received via daemon-socket) option parsing.
3: *
4: * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
5: * Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org>
6: * Copyright (C) 2002-2020 Wayne Davison
7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: #include "rsync.h"
23: #include "itypes.h"
24: #include "ifuncs.h"
25: #include <popt.h>
26:
27: extern int direct_io;
28: extern int module_id;
29: extern int local_server;
30: extern int sanitize_paths;
31: extern unsigned int module_dirlen;
32: extern filter_rule_list filter_list;
33: extern filter_rule_list daemon_filter_list;
34:
35: int make_backups = 0;
36: int make_source_backups = 0;
37:
38: /**
39: * If 1, send the whole file as literal data rather than trying to
40: * create an incremental diff.
41: *
42: * If -1, then look at whether we're local or remote and go by that.
43: *
44: * @sa disable_deltas_p()
45: **/
46: int whole_file = -1;
47:
48: int append_mode = 0;
49: int keep_dirlinks = 0;
50: int copy_dirlinks = 0;
51: int copy_links = 0;
52: int copy_devices = 0;
53: int write_devices = 0;
54: int preserve_links = 0;
55: int preserve_hard_links = 0;
56: int preserve_acls = 0;
57: int preserve_xattrs = 0;
58: int preserve_hfs_compression = 0;
59: int preserve_perms = 0;
60: int preserve_fileflags = 0;
61: int preserve_executability = 0;
62: int preserve_devices = 0;
63: int preserve_specials = 0;
64: int preserve_uid = 0;
65: int preserve_gid = 0;
66: int preserve_times = 0;
67: int preserve_atimes = 0;
68: int preserve_crtimes = 0;
69: int update_only = 0;
70: int downdate_only = 0;
71: int open_noatime = 0;
72: int cvs_exclude = 0;
73: int dry_run = 0;
74: int do_xfers = 1;
75: int do_fsync = 0;
76: int ignore_times = 0;
77: int delete_mode = 0;
78: int delete_during = 0;
79: int delete_before = 0;
80: int delete_after = 0;
81: int delete_excluded = 0;
82: int diffserv = 8;
83: char *congestion_alg = NULL;
84: int remove_source_files = 0;
85: int omit_dir_changes = 0;
86: int one_file_system = 0;
87: int protocol_version = PROTOCOL_VERSION;
88: int sparse_files = 0;
89: long sparse_files_block_size = SPARSE_WRITE_SIZE;
90: int preallocate_files = 0;
91: int do_compression = 0;
92: int do_compression_level = CLVL_NOT_SPECIFIED;
93: int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */
94: int am_server = 0;
95: int am_sender = 0;
96: int am_starting_up = 1;
97: int am_dbadmin = 0;
98: int relative_paths = -1;
99: int detect_renamed = 0;
100: int implied_dirs = 1;
101: int missing_args = 0; /* 0 = FERROR_XFER, 1 = ignore, 2 = delete */
102: int numeric_ids = 0;
103: int msgs2stderr = 2; /* Default: send errors to stderr for local & remote-shell transfers */
104: int allow_8bit_chars = 0;
105: int force_delete = 0;
106: int force_change = 0;
107: int io_timeout = 0;
108: int prune_empty_dirs = 0;
109: int use_qsort = 0;
110: char *files_from = NULL;
111: int filesfrom_fd = -1;
112: char *filesfrom_host = NULL;
113: char *db_config = NULL;
114: int eol_nulls = 0;
115: int protect_args = -1;
116: int human_readable = 1;
117: int recurse = 0;
118: int mkpath_dest_arg = 0;
119: int allow_inc_recurse = 1;
120: int xfer_dirs = -1;
121: int am_daemon = 0;
122: int db_clean, db_check, db_do_md4, db_do_md5, db_update = 1, db_lax, db_init, db_mounts;
123: int db_output_name, db_output_sum, db_output_info, db_output_unchanged, db_output_dirs, db_output_msgs;
124: int saw_db_output_opt, saw_db_sum_opt;
125: int connect_timeout = 0;
126: int keep_partial = 0;
127: int safe_symlinks = 0;
128: int copy_unsafe_links = 0;
129: int munge_symlinks = 0;
130: int size_only = 0;
131: int date_only = 0;
132: int daemon_bwlimit = 0;
133: int bwlimit = 0;
134: int fuzzy_basis = 0;
135: unsigned long sleep_asec = 0;
136: size_t bwlimit_writemax = 0;
137: int ignore_existing = 0;
138: int ignore_non_existing = 0;
139: int need_messages_from_generator = 0;
140: int checksum_files = CSF_IGNORE_FILES;
141: int max_delete = INT_MIN;
142: OFF_T max_size = -1;
143: OFF_T min_size = -1;
144: int ignore_errors = 0;
145: int modify_window = 0;
146: int ignore_case = 0;
147: int blocking_io = -1;
148: int checksum_seed = 0;
149: int inplace = 0;
150: int delay_updates = 0;
151: int32 block_size = 0;
152: time_t stop_at_utime = 0;
153: char *skip_compress = NULL;
154: char *copy_as = NULL;
155: item_list dparam_list = EMPTY_ITEM_LIST;
156:
157: /** Network address family. **/
158: int default_af_hint
159: #ifdef INET6
160: = 0; /* Any protocol */
161: #else
162: = AF_INET; /* Must use IPv4 */
163: # ifdef AF_INET6
164: # undef AF_INET6
165: # endif
166: # define AF_INET6 AF_INET /* make -6 option a no-op */
167: #endif
168:
169: /** Do not go into the background when run as --daemon. Good
170: * for debugging and required for running as a service on W32,
171: * or under Unix process-monitors. **/
172: int no_detach
173: #if defined _WIN32 || defined __WIN32__
174: = 1;
175: #else
176: = 0;
177: #endif
178:
179: int write_batch = 0;
180: int read_batch = 0;
181: int backup_dir_len = 0;
182: int backup_dir_dels_len = 0;
183: int backup_suffix_len;
184: int backup_suffix_dels_len;
185: unsigned int backup_dir_remainder;
186: unsigned int backup_dir_dels_remainder;
187:
188: char *backup_suffix = NULL;
189: char *backup_suffix_dels = NULL;
190: char *tmpdir = NULL;
191: char *partial_dir = NULL;
192: char *basis_dir[MAX_BASIS_DIRS+1];
193: char *link_by_hash_dir = NULL;
194: char *config_file = NULL;
195: char *shell_cmd = NULL;
196: char *logfile_name = NULL;
197: char *logfile_format = NULL;
198: char *stdout_format = NULL;
199: char *password_file = NULL;
200: char *source_filter = NULL;
201: char *dest_filter = NULL;
202: char *early_input_file = NULL;
203: char *rsync_path = RSYNC_PATH;
204: char *backup_dir = NULL;
205: char *backup_dir_dels = NULL;
206: char backup_dir_buf[MAXPATHLEN];
207: char backup_dir_dels_buf[MAXPATHLEN];
208: char *sockopts = NULL;
209: char *usermap = NULL;
210: char *groupmap = NULL;
211: int rsync_port = 0;
212: int alt_dest_type = 0;
213: int basis_dir_cnt = 0;
214:
215: #define DEFAULT_MAX_ALLOC (1024L * 1024 * 1024)
216: size_t max_alloc = DEFAULT_MAX_ALLOC;
217: char *max_alloc_arg;
218:
219: static int version_opt_cnt = 0;
220: static int remote_option_alloc = 0;
221: int remote_option_cnt = 0;
222: const char **remote_options = NULL;
223: const char *checksum_choice = NULL;
224: const char *compress_choice = NULL;
225:
226: int quiet = 0;
227: int output_motd = 1;
228: int log_before_transfer = 0;
229: int stdout_format_has_i = 0;
230: int stdout_format_has_o_or_i = 0;
231: int logfile_format_has_i = 0;
232: int logfile_format_has_o_or_i = 0;
233: int always_checksum = 0;
234: int list_only = 0;
235: char *tr_opt = NULL;
236:
237: #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
238: char *batch_name = NULL;
239:
240: int need_unsorted_flist = 0;
241: char *iconv_opt =
242: #ifdef ICONV_OPTION
243: ICONV_OPTION;
244: #else
245: NULL;
246: #endif
247:
248: struct chmod_mode_struct *chmod_modes = NULL;
249:
250: static const char *debug_verbosity[] = {
251: /*0*/ NULL,
252: /*1*/ NULL,
253: /*2*/ "BIND,CMD,CONNECT,DEL,DELTASUM,DUP,FILTER,FLIST,ICONV",
254: /*3*/ "ACL,BACKUP,CONNECT2,DELTASUM2,DEL2,EXIT,FILTER2,FLIST2,FUZZY,GENR,OWN,RECV,SEND,TIME",
255: /*4*/ "CMD2,DELTASUM3,DEL3,EXIT2,FLIST3,ICONV2,OWN2,PROTO,TIME2",
256: /*5*/ "CHDIR,DELTASUM4,FLIST4,FUZZY2,HASH,HASHLINK,HLINK",
257: };
258:
259: #define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1)
260:
261: static const char *info_verbosity[1+MAX_VERBOSITY] = {
262: /*0*/ NULL,
263: /*1*/ "COPY,DEL,FLIST,MISC,NAME,STATS,SYMSAFE",
264: /*2*/ "BACKUP,MISC2,MOUNT,NAME2,REMOVE,SKIP",
265: };
266:
267: #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */
268:
269: short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
270:
271: #define DEFAULT_PRIORITY 0 /* Default/implied/--verbose set values. */
272: #define HELP_PRIORITY 1 /* The help output uses this level. */
273: #define USER_PRIORITY 2 /* User-specified via --info or --debug */
274: #define LIMIT_PRIORITY 3 /* Overriding priority when limiting values. */
275:
276: #define W_CLI (1<<0) /* client side */
277: #define W_SRV (1<<1) /* server side */
278: #define W_SND (1<<2) /* sending side */
279: #define W_REC (1<<3) /* receiving side */
280:
281: struct output_struct {
282: char *name; /* The name of the info/debug flag. */
283: char *help; /* The description of the info/debug flag. */
284: uchar namelen; /* The length of the name string. */
285: uchar flag; /* The flag's value, for consistency check. */
286: uchar where; /* Bits indicating where the flag is used. */
287: uchar priority; /* See *_PRIORITY defines. */
288: };
289:
290: #define INFO_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, INFO_##flag, where, 0 }
291:
292: static struct output_struct info_words[COUNT_INFO+1] = {
293: INFO_WORD(BACKUP, W_REC, "Mention files backed up"),
294: INFO_WORD(COPY, W_REC, "Mention files copied locally on the receiving side"),
295: INFO_WORD(DEL, W_REC, "Mention deletions on the receiving side"),
296: INFO_WORD(FLIST, W_CLI, "Mention file-list receiving/sending (levels 1-2)"),
297: INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information (levels 1-2)"),
298: INFO_WORD(MOUNT, W_SND|W_REC, "Mention mounts that were found or skipped"),
299: INFO_WORD(NAME, W_SND|W_REC, "Mention 1) updated file/dir names, 2) unchanged names"),
300: INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"),
301: INFO_WORD(REMOVE, W_SND, "Mention files removed on the sending side"),
302: INFO_WORD(SKIP, W_REC, "Mention files that are skipped due to options used"),
303: INFO_WORD(STATS, W_CLI|W_SRV, "Mention statistics at end of run (levels 1-3)"),
304: INFO_WORD(SYMSAFE, W_SND|W_REC, "Mention symlinks that are unsafe"),
305: { NULL, "--info", 0, 0, 0, 0 }
306: };
307:
308: #define DEBUG_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, DEBUG_##flag, where, 0 }
309:
310: static struct output_struct debug_words[COUNT_DEBUG+1] = {
311: DEBUG_WORD(ACL, W_SND|W_REC, "Debug extra ACL info"),
312: DEBUG_WORD(BACKUP, W_REC, "Debug backup actions (levels 1-2)"),
313: DEBUG_WORD(BIND, W_CLI, "Debug socket bind actions"),
314: DEBUG_WORD(CHDIR, W_CLI|W_SRV, "Debug when the current directory changes"),
315: DEBUG_WORD(CONNECT, W_CLI, "Debug connection events (levels 1-2)"),
316: DEBUG_WORD(CMD, W_CLI, "Debug commands+options that are issued (levels 1-2)"),
317: DEBUG_WORD(DB, W_SND|W_REC, "Debug DB operations (levels 1-5)"),
318: DEBUG_WORD(DEL, W_REC, "Debug delete actions (levels 1-3)"),
319: DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"),
320: DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"),
321: DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"),
322: DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"),
323: DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"),
324: DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"),
325: DEBUG_WORD(GENR, W_REC, "Debug generator functions"),
326: DEBUG_WORD(HASH, W_SND|W_REC, "Debug hashtable code"),
327: DEBUG_WORD(HASHLINK, W_REC, "Debug hashlink code (levels 1-2)"),
328: DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions (levels 1-3)"),
329: DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv character conversions (levels 1-2)"),
330: DEBUG_WORD(IO, W_CLI|W_SRV, "Debug I/O routines (levels 1-4)"),
331: DEBUG_WORD(NSTR, W_CLI|W_SRV, "Debug negotiation strings"),
332: DEBUG_WORD(OWN, W_REC, "Debug ownership changes in users & groups (levels 1-2)"),
333: DEBUG_WORD(PROTO, W_CLI|W_SRV, "Debug protocol information"),
334: DEBUG_WORD(RECV, W_REC, "Debug receiver functions"),
335: DEBUG_WORD(SEND, W_SND, "Debug sender functions"),
336: DEBUG_WORD(TIME, W_REC, "Debug setting of modified times (levels 1-2)"),
337: { NULL, "--debug", 0, 0, 0, 0 }
338: };
339:
340: static int verbose = 0;
341: static int do_stats = 0;
342: static int do_progress = 0;
343: static int daemon_opt; /* sets am_daemon after option error-reporting */
344: static int omit_dir_times = 0;
345: static int omit_link_times = 0;
346: static int F_option_cnt = 0;
347: static int modify_window_set;
348: static int itemize_changes = 0;
349: static int refused_delete, refused_archive_part, refused_compress;
350: static int refused_partial, refused_progress, refused_delete_before;
351: static int refused_delete_during;
352: static int refused_inplace, refused_no_iconv;
353: static BOOL usermap_via_chown, groupmap_via_chown;
354: static char *outbuf_mode;
355: static char *bwlimit_arg, *max_size_arg, *min_size_arg;
356: static char tmp_partialdir[] = ".~tmp~";
357:
358: /** Local address to bind. As a character string because it's
359: * interpreted by the IPv6 layer: should be a numeric IP4 or IP6
360: * address, or a hostname. **/
361: char *bind_address;
362:
363: static void output_item_help(struct output_struct *words);
364:
365: /* This constructs a string that represents all the options set for either
366: * the --info or --debug setting, skipping any implied options (by -v, etc.).
367: * This is used both when conveying the user's options to the server, and
368: * when the help output wants to tell the user what options are implied. */
369: static char *make_output_option(struct output_struct *words, short *levels, uchar where)
370: {
371: char *str = words == info_words ? "--info=" : "--debug=";
372: int j, counts[MAX_OUT_LEVEL+1], pos, skipped = 0, len = 0, max = 0, lev = 0;
373: int word_count = words == info_words ? COUNT_INFO : COUNT_DEBUG;
374: char *buf;
375:
376: memset(counts, 0, sizeof counts);
377:
378: for (j = 0; words[j].name; j++) {
379: if (words[j].flag != j) {
380: rprintf(FERROR, "rsync: internal error on %s%s: %d != %d\n",
381: words == info_words ? "INFO_" : "DEBUG_",
382: words[j].name, words[j].flag, j);
383: exit_cleanup(RERR_UNSUPPORTED);
384: }
385: if (!(words[j].where & where))
386: continue;
387: if (words[j].priority == DEFAULT_PRIORITY) {
388: /* Implied items don't need to be mentioned. */
389: skipped++;
390: continue;
391: }
392: len += len ? 1 : strlen(str);
393: len += strlen(words[j].name);
394: len += levels[j] == 1 ? 0 : 1;
395:
396: if (words[j].priority == HELP_PRIORITY)
397: continue; /* no abbreviating for help */
398:
399: assert(levels[j] <= MAX_OUT_LEVEL);
400: if (++counts[levels[j]] > max) {
401: /* Determine which level has the most items. */
402: lev = levels[j];
403: max = counts[lev];
404: }
405: }
406:
407: /* Sanity check the COUNT_* define against the length of the table. */
408: if (j != word_count) {
409: rprintf(FERROR, "rsync: internal error: %s is wrong! (%d != %d)\n",
410: words == info_words ? "COUNT_INFO" : "COUNT_DEBUG",
411: j, word_count);
412: exit_cleanup(RERR_UNSUPPORTED);
413: }
414:
415: if (!len)
416: return NULL;
417:
418: len++;
419: buf = new_array(char, len);
420: pos = 0;
421:
422: if (skipped || max < 5)
423: lev = -1;
424: else {
425: if (lev == 0)
426: pos += snprintf(buf, len, "%sNONE", str);
427: else if (lev == 1)
428: pos += snprintf(buf, len, "%sALL", str);
429: else
430: pos += snprintf(buf, len, "%sALL%d", str, lev);
431: }
432:
433: for (j = 0; words[j].name && pos < len; j++) {
434: if (words[j].priority == DEFAULT_PRIORITY || levels[j] == lev || !(words[j].where & where))
435: continue;
436: if (pos)
437: buf[pos++] = ',';
438: else
439: pos += strlcpy(buf+pos, str, len-pos);
440: if (pos < len)
441: pos += strlcpy(buf+pos, words[j].name, len-pos);
442: /* Level 1 is implied by the name alone. */
443: if (levels[j] != 1 && pos < len)
444: buf[pos++] = '0' + levels[j];
445: }
446:
447: buf[pos] = '\0';
448:
449: return buf;
450: }
451:
452: static void parse_output_words(struct output_struct *words, short *levels, const char *str, uchar priority)
453: {
454: const char *s;
455: int j, len, lev;
456:
457: for ( ; str; str = s) {
458: if ((s = strchr(str, ',')) != NULL)
459: len = s++ - str;
460: else
461: len = strlen(str);
462: if (!len)
463: continue;
464: if (!isDigit(str)) {
465: while (len && isDigit(str+len-1))
466: len--;
467: }
468: lev = isDigit(str+len) ? atoi(str+len) : 1;
469: if (lev > MAX_OUT_LEVEL)
470: lev = MAX_OUT_LEVEL;
471: if (len == 4 && strncasecmp(str, "help", 4) == 0) {
472: output_item_help(words);
473: exit_cleanup(0);
474: }
475: if (len == 4 && strncasecmp(str, "none", 4) == 0)
476: len = lev = 0;
477: else if (len == 3 && strncasecmp(str, "all", 3) == 0)
478: len = 0;
479: for (j = 0; words[j].name; j++) {
480: if (!len
481: || (len == words[j].namelen && strncasecmp(str, words[j].name, len) == 0)) {
482: if (priority >= words[j].priority) {
483: words[j].priority = priority;
484: levels[j] = lev;
485: }
486: if (len)
487: break;
488: }
489: }
490: if (len && !words[j].name && !am_server) {
491: rprintf(FERROR, "Unknown %s item: \"%.*s\"\n",
492: words[j].help, len, str);
493: exit_cleanup(RERR_SYNTAX);
494: }
495: }
496: }
497:
498: /* Tell the user what all the info or debug flags mean. */
499: static void output_item_help(struct output_struct *words)
500: {
501: short *levels = words == info_words ? info_levels : debug_levels;
502: const char **verbosity = words == info_words ? info_verbosity : debug_verbosity;
503: char buf[128], *opt, *fmt = "%-10s %s\n";
504: int j;
505:
506: reset_output_levels();
507:
508: rprintf(FINFO, "Use OPT or OPT1 for level 1 output, OPT2 for level 2, etc.; OPT0 silences.\n");
509: rprintf(FINFO, "\n");
510: for (j = 0; words[j].name; j++)
511: rprintf(FINFO, fmt, words[j].name, words[j].help);
512: rprintf(FINFO, "\n");
513:
514: snprintf(buf, sizeof buf, "Set all %s options (e.g. all%d)",
515: words[j].help, MAX_OUT_LEVEL);
516: rprintf(FINFO, fmt, "ALL", buf);
517:
518: snprintf(buf, sizeof buf, "Silence all %s options (same as all0)",
519: words[j].help);
520: rprintf(FINFO, fmt, "NONE", buf);
521:
522: rprintf(FINFO, fmt, "HELP", "Output this help message");
523: rprintf(FINFO, "\n");
524: rprintf(FINFO, "Options added for each increase in verbose level:\n");
525:
526: for (j = 1; j <= MAX_VERBOSITY; j++) {
527: parse_output_words(words, levels, verbosity[j], HELP_PRIORITY);
528: opt = make_output_option(words, levels, W_CLI|W_SRV|W_SND|W_REC);
529: if (opt) {
530: rprintf(FINFO, "%d) %s\n", j, strchr(opt, '=')+1);
531: free(opt);
532: }
533: reset_output_levels();
534: }
535: }
536:
537: /* The --verbose option now sets info+debug flags. */
538: static void set_output_verbosity(int level, uchar priority)
539: {
540: int j;
541:
542: if (level > MAX_VERBOSITY)
543: level = MAX_VERBOSITY;
544:
545: for (j = 1; j <= level; j++) {
546: parse_output_words(info_words, info_levels, info_verbosity[j], priority);
547: parse_output_words(debug_words, debug_levels, debug_verbosity[j], priority);
548: }
549: }
550:
551: /* Limit the info+debug flag levels given a verbose-option level limit. */
552: void limit_output_verbosity(int level)
553: {
554: short info_limits[COUNT_INFO], debug_limits[COUNT_DEBUG];
555: int j;
556:
557: if (level > MAX_VERBOSITY)
558: return;
559:
560: memset(info_limits, 0, sizeof info_limits);
561: memset(debug_limits, 0, sizeof debug_limits);
562:
563: /* Compute the level limits in the above arrays. */
564: for (j = 1; j <= level; j++) {
565: parse_output_words(info_words, info_limits, info_verbosity[j], LIMIT_PRIORITY);
566: parse_output_words(debug_words, debug_limits, debug_verbosity[j], LIMIT_PRIORITY);
567: }
568:
569: for (j = 0; j < COUNT_INFO; j++) {
570: if (info_levels[j] > info_limits[j])
571: info_levels[j] = info_limits[j];
572: }
573:
574: for (j = 0; j < COUNT_DEBUG; j++) {
575: if (debug_levels[j] > debug_limits[j])
576: debug_levels[j] = debug_limits[j];
577: }
578: }
579:
580: void reset_output_levels(void)
581: {
582: int j;
583:
584: memset(info_levels, 0, sizeof info_levels);
585: memset(debug_levels, 0, sizeof debug_levels);
586:
587: for (j = 0; j < COUNT_INFO; j++)
588: info_words[j].priority = DEFAULT_PRIORITY;
589:
590: for (j = 0; j < COUNT_DEBUG; j++)
591: debug_words[j].priority = DEFAULT_PRIORITY;
592: }
593:
594: void negate_output_levels(void)
595: {
596: int j;
597:
598: for (j = 0; j < COUNT_INFO; j++)
599: info_levels[j] *= -1;
600:
601: for (j = 0; j < COUNT_DEBUG; j++)
602: debug_levels[j] *= -1;
603: }
604:
605: enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
606: OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
607: OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
608: OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
609: OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_BLOCK_SIZE,
610: OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR, OPT_SUMFILES,
611: OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS,
612: OPT_STOP_AFTER, OPT_STOP_AT,
613: OPT_REFUSED_BASE = 9000};
614:
615: static struct poptOption long_options[] = {
616: /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
617: {"help", 0, POPT_ARG_NONE, 0, OPT_HELP, 0, 0 },
618: {"version", 'V', POPT_ARG_NONE, 0, 'V', 0, 0},
619: {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 },
620: {"no-verbose", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 },
621: {"no-v", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 },
622: {"info", 0, POPT_ARG_STRING, 0, OPT_INFO, 0, 0 },
623: {"debug", 0, POPT_ARG_STRING, 0, OPT_DEBUG, 0, 0 },
624: {"stderr", 0, POPT_ARG_STRING, 0, OPT_STDERR, 0, 0 },
625: {"msgs2stderr", 0, POPT_ARG_VAL, &msgs2stderr, 1, 0, 0 },
626: {"no-msgs2stderr", 0, POPT_ARG_VAL, &msgs2stderr, 0, 0, 0 },
627: {"quiet", 'q', POPT_ARG_NONE, 0, 'q', 0, 0 },
628: {"motd", 0, POPT_ARG_VAL, &output_motd, 1, 0, 0 },
629: {"no-motd", 0, POPT_ARG_VAL, &output_motd, 0, 0, 0 },
630: {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
631: {"human-readable", 'h', POPT_ARG_NONE, 0, 'h', 0, 0},
632: {"no-human-readable",0, POPT_ARG_VAL, &human_readable, 0, 0, 0},
633: {"no-h", 0, POPT_ARG_VAL, &human_readable, 0, 0, 0},
634: {"dry-run", 'n', POPT_ARG_NONE, &dry_run, 0, 0, 0 },
635: {"archive", 'a', POPT_ARG_NONE, 0, 'a', 0, 0 },
636: {"recursive", 'r', POPT_ARG_VAL, &recurse, 2, 0, 0 },
637: {"no-recursive", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 },
638: {"no-r", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 },
639: {"inc-recursive", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 },
640: {"no-inc-recursive", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 },
641: {"i-r", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 },
642: {"no-i-r", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 },
643: {"dirs", 'd', POPT_ARG_VAL, &xfer_dirs, 2, 0, 0 },
644: {"no-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 },
645: {"no-d", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 },
646: {"old-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 },
647: {"old-d", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 },
648: {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 },
649: {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
650: {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
651: {"fileflags", 0, POPT_ARG_VAL, &preserve_fileflags, 1, 0, 0 },
652: {"no-fileflags", 0, POPT_ARG_VAL, &preserve_fileflags, 0, 0, 0 },
653: {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 },
654: {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
655: {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
656: {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
657: {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 },
658: {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
659: {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 },
660: {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
661: {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
662: {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
663: {"atimes", 'U', POPT_ARG_NONE, 0, 'U', 0, 0 },
664: {"no-atimes", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
665: {"no-U", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
666: {"open-noatime", 0, POPT_ARG_VAL, &open_noatime, 1, 0, 0 },
667: {"no-open-noatime", 0, POPT_ARG_VAL, &open_noatime, 0, 0, 0 },
668: {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 },
669: {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
670: {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 },
671: {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
672: {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
673: {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
674: {"omit-link-times", 'J', POPT_ARG_VAL, &omit_link_times, 1, 0, 0 },
675: {"no-omit-link-times",0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 },
676: {"no-J", 0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 },
677: {"omit-dir-changes", 0, POPT_ARG_NONE, &omit_dir_changes, 0, 0, 0 },
678: {"modify-window", '@', POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
679: {"super", 0, POPT_ARG_VAL, &am_root, 2, 0, 0 },
680: {"no-super", 0, POPT_ARG_VAL, &am_root, 0, 0, 0 },
681: {"fake-super", 0, POPT_ARG_VAL, &am_root, -1, 0, 0 },
682: {"owner", 'o', POPT_ARG_VAL, &preserve_uid, 1, 0, 0 },
683: {"no-owner", 0, POPT_ARG_VAL, &preserve_uid, 0, 0, 0 },
684: {"no-o", 0, POPT_ARG_VAL, &preserve_uid, 0, 0, 0 },
685: {"group", 'g', POPT_ARG_VAL, &preserve_gid, 1, 0, 0 },
686: {"no-group", 0, POPT_ARG_VAL, &preserve_gid, 0, 0, 0 },
687: {"no-g", 0, POPT_ARG_VAL, &preserve_gid, 0, 0, 0 },
688: {0, 'D', POPT_ARG_NONE, 0, 'D', 0, 0 },
689: {"no-D", 0, POPT_ARG_NONE, 0, OPT_NO_D, 0, 0 },
690: {"devices", 0, POPT_ARG_VAL, &preserve_devices, 1, 0, 0 },
691: {"no-devices", 0, POPT_ARG_VAL, &preserve_devices, 0, 0, 0 },
692: {"copy-devices", 0, POPT_ARG_NONE, ©_devices, 0, 0, 0 },
693: {"write-devices", 0, POPT_ARG_VAL, &write_devices, 1, 0, 0 },
694: {"no-write-devices", 0, POPT_ARG_VAL, &write_devices, 0, 0, 0 },
695: {"specials", 0, POPT_ARG_VAL, &preserve_specials, 1, 0, 0 },
696: {"no-specials", 0, POPT_ARG_VAL, &preserve_specials, 0, 0, 0 },
697: {"links", 'l', POPT_ARG_VAL, &preserve_links, 1, 0, 0 },
698: {"no-links", 0, POPT_ARG_VAL, &preserve_links, 0, 0, 0 },
699: {"no-l", 0, POPT_ARG_VAL, &preserve_links, 0, 0, 0 },
700: {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 },
701: {"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 },
702: {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 },
703: {"munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 1, 0, 0 },
704: {"no-munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 0, 0, 0 },
705: {"copy-dirlinks", 'k', POPT_ARG_NONE, ©_dirlinks, 0, 0, 0 },
706: {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
707: {"hard-links", 'H', POPT_ARG_NONE, 0, 'H', 0, 0 },
708: {"no-hard-links", 0, POPT_ARG_VAL, &preserve_hard_links, 0, 0, 0 },
709: {"no-H", 0, POPT_ARG_VAL, &preserve_hard_links, 0, 0, 0 },
710: {"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 },
711: {"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
712: {"no-R", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
713: {"implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 },
714: {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
715: {"i-d", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 },
716: {"no-i-d", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
717: {"chmod", 0, POPT_ARG_STRING, 0, OPT_CHMOD, 0, 0 },
718: {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
719: {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
720: {"date-only", 0, POPT_ARG_NONE, &date_only, 0, 0, 0 },
721: {"one-file-system", 'x', POPT_ARG_NONE, 0, 'x', 0, 0 },
722: {"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
723: {"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 },
724: {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
725: {"downdate", 'w', POPT_ARG_NONE, &downdate_only, 0, 0, 0 },
726: {"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 },
727: {"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 },
728: {"ignore-existing", 0, POPT_ARG_NONE, &ignore_existing, 0, 0, 0 },
729: {"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
730: {"min-size", 0, POPT_ARG_STRING, &min_size_arg, OPT_MIN_SIZE, 0, 0 },
731: {"max-alloc", 0, POPT_ARG_STRING, &max_alloc_arg, 0, 0, 0 },
732: {"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 },
733: {"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
734: {"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
735: {"sparse-block", 0, POPT_ARG_LONG, &sparse_files_block_size, 0, 0, 0 },
736: {"preallocate", 0, POPT_ARG_NONE, &preallocate_files, 0, 0, 0},
737: {"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 },
738: {"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 },
739: {"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 },
740: {"append-verify", 0, POPT_ARG_VAL, &append_mode, 2, 0, 0 },
741: {"no-append", 0, POPT_ARG_VAL, &append_mode, 0, 0, 0 },
742: {"del", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 },
743: {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 },
744: {"delete-before", 0, POPT_ARG_NONE, &delete_before, 0, 0, 0 },
745: {"delete-during", 0, POPT_ARG_VAL, &delete_during, 1, 0, 0 },
746: {"delete-delay", 0, POPT_ARG_VAL, &delete_during, 2, 0, 0 },
747: {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 },
748: {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 },
749: {"delete-missing-args",0,POPT_BIT_SET, &missing_args, 2, 0, 0 },
750: {"ignore-missing-args",0,POPT_BIT_SET, &missing_args, 1, 0, 0 },
751: {"remove-sent-files",0, POPT_ARG_VAL, &remove_source_files, 2, 0, 0 }, /* deprecated */
752: {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 },
753: {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 },
754: {"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 },
755: {"force-delete", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 },
756: {"no-force-delete", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 },
757: {"force-change", 0, POPT_ARG_VAL, &force_change, ALL_IMMUTABLE, 0, 0 },
758: {"no-force-change", 0, POPT_ARG_VAL, &force_change, 0, 0, 0 },
759: {"force-uchange", 0, POPT_ARG_VAL, &force_change, USR_IMMUTABLE, 0, 0 },
760: {"force-schange", 0, POPT_ARG_VAL, &force_change, SYS_IMMUTABLE, 0, 0 },
761: {"hfs-compression", 0, POPT_ARG_VAL, &preserve_hfs_compression, 1, 0, 0 },
762: {"no-hfs-compression",0, POPT_ARG_VAL, &preserve_hfs_compression, 0, 0, 0 },
763: {"protect-decmpfs", 0, POPT_ARG_VAL, &preserve_hfs_compression, 2, 0, 0 },
764: {"no-protect-decmpfs",0, POPT_ARG_VAL, &preserve_hfs_compression, 0, 0, 0 },
765: {"ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 1, 0, 0 },
766: {"no-ignore-errors", 0, POPT_ARG_VAL, &ignore_errors, 0, 0, 0 },
767: {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
768: {0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 },
769: {"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
770: {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
771: {"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 },
772: {"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 },
773: {"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 },
774: {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 },
775: {"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 },
776: {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 },
777: {"no-W", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 },
778: {"checksum", 'c', POPT_ARG_VAL, &always_checksum, 1, 0, 0 },
779: {"no-checksum", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
780: {"no-c", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
781: {"checksum-choice", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 },
782: {"cc", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 },
783: {"sumfiles", 0, POPT_ARG_STRING, 0, OPT_SUMFILES, 0, 0 },
784: {"block-size", 'B', POPT_ARG_STRING, 0, OPT_BLOCK_SIZE, 0, 0 },
785: {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
786: {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
787: {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
788: {"clone-dest", 0, POPT_ARG_STRING, 0, OPT_CLONE_DEST, 0, 0 },
789: {"fuzzy", 'y', POPT_ARG_NONE, 0, 'y', 0, 0 },
790: {"no-fuzzy", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
791: {"no-y", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 },
792: {"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 },
793: {"old-compress", 0, POPT_ARG_NONE, 0, OPT_OLD_COMPRESS, 0, 0 },
794: {"new-compress", 0, POPT_ARG_NONE, 0, OPT_NEW_COMPRESS, 0, 0 },
795: {"no-compress", 0, POPT_ARG_NONE, 0, OPT_NO_COMPRESS, 0, 0 },
796: {"no-z", 0, POPT_ARG_NONE, 0, OPT_NO_COMPRESS, 0, 0 },
797: {"compress-choice", 0, POPT_ARG_STRING, &compress_choice, 0, 0, 0 },
798: {"zc", 0, POPT_ARG_STRING, &compress_choice, 0, 0, 0 },
799: {"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 },
800: {"compress-level", 0, POPT_ARG_INT, &do_compression_level, 0, 0, 0 },
801: {"zl", 0, POPT_ARG_INT, &do_compression_level, 0, 0, 0 },
802: {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
803: {"progress", 0, POPT_ARG_VAL, &do_progress, 1, 0, 0 },
804: {"no-progress", 0, POPT_ARG_VAL, &do_progress, 0, 0, 0 },
805: {"partial", 0, POPT_ARG_VAL, &keep_partial, 1, 0, 0 },
806: {"no-partial", 0, POPT_ARG_VAL, &keep_partial, 0, 0, 0 },
807: {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
808: {"delay-updates", 0, POPT_ARG_VAL, &delay_updates, 1, 0, 0 },
809: {"no-delay-updates", 0, POPT_ARG_VAL, &delay_updates, 0, 0, 0 },
810: {"direct-io", 'n', POPT_ARG_VAL, &direct_io, 1, 0, 0 },
811: {"no-direct-io", 0, POPT_ARG_VAL, &direct_io, 0, 0, 0 },
812: {"prune-empty-dirs",'m', POPT_ARG_VAL, &prune_empty_dirs, 1, 0, 0 },
813: {"no-prune-empty-dirs",0,POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 },
814: {"no-m", 0, POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 },
815: {"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 },
816: {"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 },
817: {"out-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 },
818: {"log-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 }, /* DEPRECATED */
819: {"itemize-changes", 'i', POPT_ARG_NONE, 0, 'i', 0, 0 },
820: {"no-itemize-changes",0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 },
821: {"no-i", 0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 },
822: {"slow-down", 0, POPT_ARG_LONG, &sleep_asec, 0, 0, 0 },
823: {"bwlimit", 0, POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 },
824: {"no-bwlimit", 0, POPT_ARG_VAL, &bwlimit, 0, 0, 0 },
825: {"backup", 'b', POPT_ARG_VAL, &make_backups, 2, 0, 0 },
826: {"backup-deleted", 0, POPT_ARG_VAL, &make_backups, 1, 0, 0 },
827: {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 },
828: {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
829: {"backup-dir-dels", 0, POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
830: {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
831: {"suffix-dels", 0, POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
832: {"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 },
833: {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
834: {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
835: {"only-write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_ONLY_WRITE_BATCH, 0, 0 },
836: {"ignore-case", 0, POPT_ARG_VAL, &ignore_case, 1, 0, 0 },
837: {"no-ignore-case", 0, POPT_ARG_VAL, &ignore_case, 0, 0, 0 },
838: {"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 },
839: {"from0", '0', POPT_ARG_VAL, &eol_nulls, 1, 0, 0},
840: {"no-from0", 0, POPT_ARG_VAL, &eol_nulls, 0, 0, 0},
841: {"protect-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0},
842: {"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
843: {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
844: {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 },
845: {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 },
846: {"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 },
847: {"groupmap", 0, POPT_ARG_STRING, 0, OPT_GROUPMAP, 0, 0 },
848: {"chown", 0, POPT_ARG_STRING, 0, OPT_CHOWN, 0, 0 },
849: {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
850: {"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 },
851: {"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 },
852: {"no-contimeout", 0, POPT_ARG_VAL, &connect_timeout, 0, 0, 0 },
853: {"fsync", 0, POPT_ARG_NONE, &do_fsync, 0, 0, 0 },
854: {"stop-after", 0, POPT_ARG_STRING, 0, OPT_STOP_AFTER, 0, 0 },
855: {"time-limit", 0, POPT_ARG_STRING, 0, OPT_STOP_AFTER, 0, 0 }, /* earlier stop-after name */
856: {"stop-at", 0, POPT_ARG_STRING, 0, OPT_STOP_AT, 0, 0 },
857: {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
858: {"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
859: {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
860: {"iconv", 0, POPT_ARG_STRING, &iconv_opt, 0, 0, 0 },
861: {"no-iconv", 0, POPT_ARG_NONE, 0, OPT_NO_ICONV, 0, 0 },
862: {"tr", 0, POPT_ARG_STRING, &tr_opt, 0, 0, 0 },
863: {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
864: {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
865: {"8-bit-output", '8', POPT_ARG_VAL, &allow_8bit_chars, 1, 0, 0 },
866: {"no-8-bit-output", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 },
867: {"no-8", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 },
868: {"mkpath", 0, POPT_ARG_VAL, &mkpath_dest_arg, 1, 0, 0 },
869: {"no-mkpath", 0, POPT_ARG_VAL, &mkpath_dest_arg, 0, 0, 0 },
870: {"qsort", 0, POPT_ARG_NONE, &use_qsort, 0, 0, 0 },
871: {"copy-as", 0, POPT_ARG_STRING, ©_as, 0, 0, 0 },
872: {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
873: {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
874: {"sockopts", 0, POPT_ARG_STRING, &sockopts, 0, 0, 0 },
875: {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
876: {"early-input", 0, POPT_ARG_STRING, &early_input_file, 0, 0, 0 },
877: {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
878: {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
879: {"source-filter", 0, POPT_ARG_STRING, &source_filter, 0, 0, 0 },
880: {"dest-filter", 0, POPT_ARG_STRING, &dest_filter, 0, 0, 0 },
881: {"outbuf", 0, POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 },
882: {"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
883: {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
884: {"congestion-alg", 0, POPT_ARG_STRING, &congestion_alg, 0, 0, 0 },
885: {"diffserv", 0, POPT_ARG_INT, &diffserv, 0, 0, 0 },
886: {"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
887: {"server", 0, POPT_ARG_NONE, 0, OPT_SERVER, 0, 0 },
888: {"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 },
889: /* All the following options switch us into daemon-mode option-parsing. */
890: {"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
891: {"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
892: {"dparam", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
893: {"detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
894: {"no-detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
895: /* All the following options switch us into DB-admin option-parsing. */
896: {"db-help", 0, POPT_ARG_NONE, 0, OPT_DBONLY, 0, 0 },
897: {"db-only", 0, POPT_ARG_STRING, 0, OPT_DBONLY, 0, 0 },
898: {0,0,0,0, 0, 0, 0}
899: };
900:
901: static struct poptOption long_daemon_options[] = {
902: /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
903: {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
904: {"bwlimit", 0, POPT_ARG_INT, &daemon_bwlimit, 0, 0, 0 },
905: {"config", 0, POPT_ARG_STRING, &config_file, 0, 0, 0 },
906: {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 },
907: {"dparam", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
908: {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
909: {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
910: {"detach", 0, POPT_ARG_VAL, &no_detach, 0, 0, 0 },
911: {"no-detach", 0, POPT_ARG_VAL, &no_detach, 1, 0, 0 },
912: {"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 },
913: {"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 },
914: {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
915: {"sockopts", 0, POPT_ARG_STRING, &sockopts, 0, 0, 0 },
916: {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
917: {"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 },
918: {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
919: {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 },
920: {"no-verbose", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 },
921: {"no-v", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 },
922: {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
923: {0,0,0,0, 0, 0, 0}
924: };
925:
926: static struct poptOption long_dbonly_options[] = {
927: /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
928: {"check", 'c', POPT_ARG_NONE, &db_check, 0, 0, 0},
929: {"clean", 0, POPT_ARG_NONE, &db_clean, 0, 0, 0},
930: {"db", 0, POPT_ARG_STRING, &db_config, 0, 0, 0 },
931: {"db-only", 0, POPT_ARG_STRING, &db_config, 0, 0, 0 },
932: {"db-lax", 0, POPT_ARG_VAL, &db_lax, 1, 0, 0 },
933: {"no-db-lax", 0, POPT_ARG_VAL, &db_lax, 0, 0, 0 },
934: {"info", 0, POPT_ARG_STRING, 0, OPT_INFO, 0, 0 },
935: {"debug", 0, POPT_ARG_STRING, 0, OPT_DEBUG, 0, 0 },
936: {"update", 'u', POPT_ARG_VAL, &db_update, 1, 0, 0 },
937: {"no-update", 'N', POPT_ARG_VAL, &db_update, 0, 0, 0 },
938: {"no-u", 0, POPT_ARG_VAL, &db_update, 0, 0, 0 },
939: {"output", 'o', POPT_ARG_STRING, 0, 'o', 0, 0 },
940: {"recursive", 'r', POPT_ARG_VAL, &recurse, 1, 0, 0 },
941: {"no-recursive", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 },
942: {"no-r", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 },
943: {"sums", 's', POPT_ARG_STRING, 0, 's', 0, 0 },
944: {"init", 0, POPT_ARG_NONE, &db_init, 0, 0, 0 },
945: {"mounts", 0, POPT_ARG_NONE, &db_mounts, 0, 0, 0 },
946: {"quiet", 'q', POPT_ARG_NONE, &quiet, 0, 0, 0 },
947: {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
948: {"db-help", 0, POPT_ARG_NONE, 0, 'h', 0, 0 },
949: {0,0,0,0, 0, 0, 0}
950: };
951:
952: static char err_buf[200];
953:
954:
955: /**
956: * Store the option error message, if any, so that we can log the
957: * connection attempt (which requires parsing the options), and then
958: * show the error later on.
959: **/
960: void option_error(void)
961: {
962: if (!err_buf[0]) {
963: strlcpy(err_buf, "Error parsing options: option may "
964: "be supported on client but not on server?\n",
965: sizeof err_buf);
966: }
967:
968: rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
969: io_flush(MSG_FLUSH);
970: msleep(20);
971: }
972:
973:
974: static void parse_one_refuse_match(int negated, const char *ref, const struct poptOption *list_end)
975: {
976: struct poptOption *op;
977: char shortName[2];
978: int is_wild = strpbrk(ref, "*?[") != NULL;
979: int found_match = 0;
980:
981: shortName[1] = '\0';
982:
983: if (strcmp("a", ref) == 0 || strcmp("archive", ref) == 0) {
984: ref = "[ardlptgoD]";
985: is_wild = 1;
986: }
987:
988: for (op = long_options; op != list_end; op++) {
989: *shortName = op->shortName;
990: if ((op->longName && wildmatch(ref, op->longName))
991: || (*shortName && wildmatch(ref, shortName))) {
992: if (op->descrip[1] == '*')
993: op->descrip = negated ? "a*" : "r*";
994: else if (!is_wild)
995: op->descrip = negated ? "a=" : "r=";
996: found_match = 1;
997: if (!is_wild)
998: break;
999: }
1000: }
1001:
1002: if (!found_match)
1003: rprintf(FLOG, "No match for refuse-options string \"%s\"\n", ref);
1004: }
1005:
1006:
1007: /**
1008: * Tweak the option table to disable all options that the rsyncd.conf
1009: * file has told us to refuse.
1010: **/
1011: static void set_refuse_options(void)
1012: {
1013: struct poptOption *op, *list_end = NULL;
1014: char *cp, *ref = lp_refuse_options(module_id);
1015: int negated;
1016:
1017: if (!ref)
1018: ref = "";
1019:
1020: if (!am_daemon)
1021: ref = "";
1022:
1023: /* We abuse the descrip field in poptOption to make it easy to flag which options
1024: * are refused (since we don't use it otherwise). Start by marking all options
1025: * as "a"ccepted with a few options also marked as non-wild. */
1026: for (op = long_options; ; op++) {
1027: const char *longName = op->longName ? op->longName : "";
1028: if (!op->longName && !op->shortName) {
1029: list_end = op;
1030: break;
1031: }
1032: if (!am_daemon
1033: || op->shortName == 'e' /* Required for compatibility flags */
1034: || op->shortName == '0' /* --from0 just modifies --files-from, so refuse that instead (or not) */
1035: || op->shortName == 's' /* --protect-args is always OK */
1036: || op->shortName == 'n' /* --dry-run is always OK */
1037: || strcmp("iconv", longName) == 0
1038: || strcmp("no-iconv", longName) == 0
1039: || strcmp("checksum-seed", longName) == 0
1040: || strcmp("copy-devices", longName) == 0 /* disable wild-match (it gets refused below) */
1041: || strcmp("write-devices", longName) == 0 /* disable wild-match (it gets refused below) */
1042: || strcmp("log-format", longName) == 0 /* aka out-format (NOT log-file-format) */
1043: || strcmp("sender", longName) == 0
1044: || strcmp("server", longName) == 0)
1045: op->descrip = "a="; /* exact-match only */
1046: else
1047: op->descrip = "a*"; /* wild-card-able */
1048: }
1049: assert(list_end != NULL);
1050:
1051: if (am_daemon) { /* Refused by default, but can be accepted via a negated exact match. */
1052: parse_one_refuse_match(0, "copy-devices", list_end);
1053: parse_one_refuse_match(0, "write-devices", list_end);
1054: }
1055:
1056: while (1) {
1057: while (*ref == ' ') ref++;
1058: if (!*ref)
1059: break;
1060: if ((cp = strchr(ref, ' ')) != NULL)
1061: *cp = '\0';
1062: negated = *ref == '!';
1063: if (negated && ref[1])
1064: ref++;
1065: parse_one_refuse_match(negated, ref, list_end);
1066: if (!cp)
1067: break;
1068: *cp = ' ';
1069: ref = cp + 1;
1070: }
1071:
1072: if (*lp_link_by_hash_dir(module_id))
1073: parse_one_refuse_match(0, "link-by-hash", list_end);
1074:
1075: if (am_daemon) {
1076: #ifdef ICONV_OPTION
1077: if (!*lp_charset(module_id))
1078: parse_one_refuse_match(0, "iconv", list_end);
1079: #endif
1080: parse_one_refuse_match(0, "log-file*", list_end);
1081: parse_one_refuse_match(0, "db", list_end);
1082: parse_one_refuse_match(0, "db-lax", list_end);
1083: }
1084:
1085: #ifndef SUPPORT_ATIMES
1086: parse_one_refuse_match(0, "atimes", list_end);
1087: #endif
1088: #ifndef SUPPORT_HARD_LINKS
1089: parse_one_refuse_match(0, "link-dest", list_end);
1090: #endif
1091: #ifndef FICLONE
1092: parse_one_refuse_match(0, "clone-dest", list_end);
1093: #endif
1094: #ifndef HAVE_MKTIME
1095: parse_one_refuse_match(0, "stop-at", list_end);
1096: #endif
1097: #ifndef ICONV_OPTION
1098: parse_one_refuse_match(0, "iconv", list_end);
1099: #endif
1100: #ifndef HAVE_SETVBUF
1101: parse_one_refuse_match(0, "outbuf", list_end);
1102: #endif
1103: #ifndef SUPPORT_CRTIMES
1104: parse_one_refuse_match(0, "crtimes", list_end);
1105: #endif
1106: #ifndef SUPPORT_FILEFLAGS
1107: parse_one_refuse_match(0, "fileflags", list_end);
1108: #endif
1109: #ifndef SUPPORT_FORCE_CHANGE
1110: parse_one_refuse_match(0, "force-change", list_end);
1111: parse_one_refuse_match(0, "force-uchange", list_end);
1112: parse_one_refuse_match(0, "force-schange", list_end);
1113: #endif
1114: #ifndef SUPPORT_HFS_COMPRESSION
1115: parse_one_refuse_match(0, "hfs-compression", list_end);
1116: parse_one_refuse_match(0, "protect-decmpfs", list_end);
1117: #endif
1118:
1119: /* Now we use the descrip values to actually mark the options for refusal. */
1120: for (op = long_options; op != list_end; op++) {
1121: int refused = op->descrip[0] == 'r';
1122: op->descrip = NULL;
1123: if (!refused)
1124: continue;
1125: if (op->argInfo == POPT_ARG_VAL)
1126: op->argInfo = POPT_ARG_NONE;
1127: op->val = (op - long_options) + OPT_REFUSED_BASE;
1128: /* The following flags are set to let us easily check an implied option later in the code. */
1129: switch (op->shortName) {
1130: case 'r': case 'd': case 'l': case 'p':
1131: case 't': case 'g': case 'o': case 'D':
1132: refused_archive_part = op->val;
1133: break;
1134: case 'z':
1135: refused_compress = op->val;
1136: break;
1137: case '\0':
1138: if (strcmp("delete", op->longName) == 0)
1139: refused_delete = op->val;
1140: else if (strcmp("delete-before", op->longName) == 0)
1141: refused_delete_before = op->val;
1142: else if (strcmp("delete-during", op->longName) == 0)
1143: refused_delete_during = op->val;
1144: else if (strcmp("partial", op->longName) == 0)
1145: refused_partial = op->val;
1146: else if (strcmp("progress", op->longName) == 0)
1147: refused_progress = op->val;
1148: else if (strcmp("inplace", op->longName) == 0)
1149: refused_inplace = op->val;
1150: else if (strcmp("no-iconv", op->longName) == 0)
1151: refused_no_iconv = op->val;
1152: break;
1153: }
1154: }
1155: }
1156:
1157:
1158: static int count_args(const char **argv)
1159: {
1160: int i = 0;
1161:
1162: if (argv) {
1163: while (argv[i] != NULL)
1164: i++;
1165: }
1166:
1167: return i;
1168: }
1169:
1170: /* If the size_arg is an invalid string or the value is < min_value, an error
1171: * is put into err_buf & the return is -1. Note that this parser does NOT
1172: * support negative numbers, so a min_value < 0 doesn't make any sense. */
1173: static ssize_t parse_size_arg(const char *size_arg, char def_suf, const char *opt_name,
1174: ssize_t min_value, ssize_t max_value, BOOL unlimited_0)
1175: {
1176: int reps, mult, len;
1177: const char *arg, *err = "invalid", *min_max = NULL;
1178: ssize_t limit = -1, size = 1;
1179:
1180: for (arg = size_arg; isDigit(arg); arg++) {}
1181: if (*arg == '.' || *arg == get_decimal_point()) /* backward compatibility: always allow '.' */
1182: for (arg++; isDigit(arg); arg++) {}
1183: switch (*arg && *arg != '+' && *arg != '-' ? *arg++ : def_suf) {
1184: case 'b': case 'B':
1185: reps = 0;
1186: break;
1187: case 'k': case 'K':
1188: reps = 1;
1189: break;
1190: case 'm': case 'M':
1191: reps = 2;
1192: break;
1193: case 'g': case 'G':
1194: reps = 3;
1195: break;
1196: case 't': case 'T':
1197: reps = 4;
1198: break;
1199: case 'p': case 'P':
1200: reps = 5;
1201: break;
1202: default:
1203: goto failure;
1204: }
1205: if (*arg == 'b' || *arg == 'B')
1206: mult = 1000, arg++;
1207: else if (!*arg || *arg == '+' || *arg == '-')
1208: mult = 1024;
1209: else if (strncasecmp(arg, "ib", 2) == 0)
1210: mult = 1024, arg += 2;
1211: else
1212: goto failure;
1213: while (reps--)
1214: size *= mult;
1215: size *= atof(size_arg);
1216: if ((*arg == '+' || *arg == '-') && arg[1] == '1' && arg != size_arg)
1217: size += atoi(arg), arg += 2;
1218: if (*arg)
1219: goto failure;
1220: if (size < 0 || (max_value >= 0 && size > max_value)) {
1221: err = "too large";
1222: min_max = "max";
1223: limit = max_value;
1224: goto failure;
1225: }
1226: if (size < min_value && (!unlimited_0 || size != 0)) {
1227: err = "too small";
1228: min_max = "min";
1229: limit = min_value;
1230: goto failure;
1231: }
1232: return size;
1233:
1234: failure:
1235: len = snprintf(err_buf, sizeof err_buf - 1, "--%s=%s is %s", opt_name, size_arg, err);
1236: if (min_max && limit >= 0 && len < (int)sizeof err_buf - 10) {
1237: len += snprintf(err_buf + len, sizeof err_buf - len - 1, " (%s: %s%s)",
1238: min_max, do_big_num(limit, 3, NULL),
1239: unlimited_0 && min_max[1] == 'i' ? " or 0 for unlimited" : "");
1240: }
1241: err_buf[len] = '\n';
1242: err_buf[len+1] = '\0';
1243: return -1;
1244: }
1245:
1246: #ifdef HAVE_MKTIME
1247: /* Allow the user to specify a time in the format yyyy-mm-ddThh:mm while
1248: * also allowing abbreviated data. For instance, if the time is omitted,
1249: * it defaults to midnight. If the date is omitted, it defaults to the
1250: * next possible date in the future with the specified time. Even the
1251: * year or year-month can be omitted, again defaulting to the next date
1252: * in the future that matches the specified information. A 2-digit year
1253: * is also OK, as is using '/' instead of '-'. */
1254: static time_t parse_time(const char *arg)
1255: {
1256: const char *cp;
1257: time_t val, now = time(NULL);
1258: struct tm t, *today = localtime(&now);
1259: int in_date, old_mday, n;
1260:
1261: memset(&t, 0, sizeof t);
1262: t.tm_year = t.tm_mon = t.tm_mday = -1;
1263: t.tm_hour = t.tm_min = t.tm_isdst = -1;
1264: cp = arg;
1265: if (*cp == 'T' || *cp == 't' || *cp == ':') {
1266: in_date = *cp == ':' ? 0 : -1;
1267: cp++;
1268: } else
1269: in_date = 1;
1270: for ( ; ; cp++) {
1271: if (!isDigit(cp))
1272: return (time_t)-1;
1273: n = 0;
1274: do {
1275: n = n * 10 + *cp++ - '0';
1276: } while (isDigit(cp));
1277: if (*cp == ':')
1278: in_date = 0;
1279: if (in_date > 0) {
1280: if (t.tm_year != -1)
1281: return (time_t)-1;
1282: t.tm_year = t.tm_mon;
1283: t.tm_mon = t.tm_mday;
1284: t.tm_mday = n;
1285: if (!*cp)
1286: break;
1287: if (*cp == 'T' || *cp == 't') {
1288: if (!cp[1])
1289: break;
1290: in_date = -1;
1291: } else if (*cp != '-' && *cp != '/')
1292: return (time_t)-1;
1293: continue;
1294: }
1295: if (t.tm_hour != -1)
1296: return (time_t)-1;
1297: t.tm_hour = t.tm_min;
1298: t.tm_min = n;
1299: if (!*cp) {
1300: if (in_date < 0)
1301: return (time_t)-1;
1302: break;
1303: }
1304: if (*cp != ':')
1305: return (time_t)-1;
1306: in_date = 0;
1307: }
1308:
1309: in_date = 0;
1310: if (t.tm_year < 0) {
1311: t.tm_year = today->tm_year;
1312: in_date = 1;
1313: } else if (t.tm_year < 100) {
1314: while (t.tm_year < today->tm_year)
1315: t.tm_year += 100;
1316: } else
1317: t.tm_year -= 1900;
1318: if (t.tm_mon < 0) {
1319: t.tm_mon = today->tm_mon;
1320: in_date = 2;
1321: } else
1322: t.tm_mon--;
1323: if (t.tm_mday < 0) {
1324: t.tm_mday = today->tm_mday;
1325: in_date = 3;
1326: }
1327:
1328: n = 0;
1329: if (t.tm_min < 0) {
1330: t.tm_hour = t.tm_min = 0;
1331: } else if (t.tm_hour < 0) {
1332: if (in_date != 3)
1333: return (time_t)-1;
1334: in_date = 0;
1335: t.tm_hour = today->tm_hour;
1336: n = 60*60;
1337: }
1338:
1339: /* Note that mktime() might change a too-large tm_mday into the start of
1340: * the following month which we need to undo in the following code! */
1341: old_mday = t.tm_mday;
1342: if (t.tm_hour > 23 || t.tm_min > 59
1343: || t.tm_mon < 0 || t.tm_mon >= 12
1344: || t.tm_mday < 1 || t.tm_mday > 31
1345: || (val = mktime(&t)) == (time_t)-1)
1346: return (time_t)-1;
1347:
1348: while (in_date && (val <= now || t.tm_mday < old_mday)) {
1349: switch (in_date) {
1350: case 3:
1351: old_mday = ++t.tm_mday;
1352: break;
1353: case 2:
1354: if (t.tm_mday < old_mday)
1355: t.tm_mday = old_mday; /* The month already got bumped forward */
1356: else if (++t.tm_mon == 12) {
1357: t.tm_mon = 0;
1358: t.tm_year++;
1359: }
1360: break;
1361: case 1:
1362: if (t.tm_mday < old_mday) {
1363: /* mon==1 mday==29 got bumped to mon==2 */
1364: if (t.tm_mon != 2 || old_mday != 29)
1365: return (time_t)-1;
1366: t.tm_mon = 1;
1367: t.tm_mday = 29;
1368: }
1369: t.tm_year++;
1370: break;
1371: }
1372: if ((val = mktime(&t)) == (time_t)-1) {
1373: /* This code shouldn't be needed, as mktime() should auto-round to the next month. */
1374: if (in_date != 3 || t.tm_mday <= 28)
1375: return (time_t)-1;
1376: t.tm_mday = old_mday = 1;
1377: in_date = 2;
1378: }
1379: }
1380: if (n) {
1381: while (val <= now)
1382: val += n;
1383: }
1384: return val;
1385: }
1386: #endif
1387:
1388: static void create_refuse_error(int which)
1389: {
1390: const char *msg;
1391: if (am_daemon)
1392: msg = "The server is configured to refuse";
1393: else if (am_server)
1394: msg = "The server does not support";
1395: else
1396: msg = "This rsync does not support";
1397:
1398: /* The "which" value is the index + OPT_REFUSED_BASE. */
1399: struct poptOption *op = &long_options[which - OPT_REFUSED_BASE];
1400: int n = snprintf(err_buf, sizeof err_buf, "%s --%s\n", msg, op->longName) - 1;
1401: if (op->shortName)
1402: snprintf(err_buf + n, sizeof err_buf - n, " (-%c)\n", op->shortName);
1403: }
1404:
1405: static NORETURN void parse_dbonly_args(int argc, const char **argv)
1406: {
1407: poptContext pc = poptGetContext(RSYNC_NAME, argc, argv, long_dbonly_options, 0);
1408: const char *arg;
1409: int opt;
1410:
1411: recurse = 1;
1412: am_dbadmin = 1;
1413:
1414: while ((opt = poptGetNextOpt(pc)) != -1) {
1415: const char *cp;
1416: switch (opt) {
1417: case 'o':
1418: for (cp = poptGetOptArg(pc); *cp; cp++) {
1419: switch (toLower(cp)) {
1420: case 'n':
1421: db_output_name = 1;
1422: break;
1423: case 's':
1424: case 'c':
1425: db_output_sum = db_output_name = 1;
1426: break;
1427: case 'i':
1428: db_output_info = db_output_name = 1;
1429: break;
1430: case 'u':
1431: db_output_unchanged = db_output_name = 1;
1432: break;
1433: case 'd':
1434: db_output_dirs = 1;
1435: break;
1436: }
1437: }
1438: saw_db_output_opt = 1;
1439: break;
1440:
1441: case 's':
1442: for (cp = poptGetOptArg(pc); *cp; cp++) {
1443: switch (*cp) {
1444: case '4':
1445: db_do_md4 = 1;
1446: break;
1447: case '5':
1448: db_do_md5 = 1;
1449: break;
1450: }
1451: }
1452: saw_db_sum_opt = 1;
1453: break;
1454:
1455: case 'h':
1456: dbonly_usage(FINFO);
1457: exit_cleanup(0);
1458:
1459: case OPT_INFO:
1460: arg = poptGetOptArg(pc);
1461: parse_output_words(info_words, info_levels, arg, USER_PRIORITY);
1462: break;
1463:
1464: case OPT_DEBUG:
1465: arg = poptGetOptArg(pc);
1466: parse_output_words(debug_words, debug_levels, arg, USER_PRIORITY);
1467: break;
1468:
1469: default:
1470: rprintf(FERROR,
1471: "rsyncdb: %s: %s\n",
1472: poptBadOption(pc, POPT_BADOPTION_NOALIAS),
1473: poptStrerror(opt));
1474: goto dbonly_usage;
1475: }
1476: }
1477:
1478: if (!db_config) {
1479: rprintf(FERROR, "You must specify the --db=FILE option.\n");
1480: dbonly_usage:
1481: rprintf(FERROR,
1482: "(Type \"rsyncdb --help\" for assistance.)\n");
1483: exit_cleanup(RERR_SYNTAX);
1484: }
1485:
1486: if (!saw_db_output_opt && !quiet) {
1487: db_output_dirs = db_output_name = 1;
1488: if (db_check)
1489: db_output_info = 1;
1490: }
1491: if (!quiet)
1492: db_output_msgs = 1;
1493: if (!saw_db_sum_opt)
1494: db_do_md5 = 1;
1495:
1496: am_starting_up = 0;
1497: run_dbonly(poptGetArgs(pc));
1498: exit(42); /* NOT REACHED */
1499: }
1500:
1501: /* This is used to make sure that --daemon & --server cannot be aliased to
1502: * something else. These options have always disabled popt aliases for the
1503: * parsing of a daemon or server command-line, but we have to make sure that
1504: * these options cannot vanish so that the alias disabling can take effect. */
1505: static void popt_unalias(poptContext con, const char *opt)
1506: {
1507: struct poptAlias unalias;
1508:
1509: memset(&unalias, 0, sizeof unalias);
1510:
1511: unalias.longName = opt + 2; /* point past the leading "--" */
1512: unalias.argc = 1;
1513: unalias.argv = new_array0(const char*, 2);
1514: unalias.argv[0] = strdup(opt);
1515:
1516: poptAddAlias(con, unalias, 0);
1517: }
1518:
1519: char *alt_dest_opt(int type)
1520: {
1521: if (!type)
1522: type = alt_dest_type;
1523:
1524: switch (type) {
1525: case COMPARE_DEST:
1526: return "--compare-dest";
1527: case COPY_DEST:
1528: return "--copy-dest";
1529: case LINK_DEST:
1530: return "--link-dest";
1531: case CLONE_DEST:
1532: return "--clone-dest";
1533: default:
1534: NOISY_DEATH("Unknown alt_dest_opt type");
1535: }
1536: }
1537:
1538: /**
1539: * Process command line arguments. Called on both local and remote.
1540: *
1541: * @retval 1 if all options are OK; with globals set to appropriate
1542: * values
1543: *
1544: * @retval 0 on error, with err_buf containing an explanation
1545: **/
1546: int parse_arguments(int *argc_p, const char ***argv_p)
1547: {
1548: static poptContext pc;
1549: const char *arg, **argv = *argv_p;
1550: int argc = *argc_p;
1551: int opt, want_dest_type;
1552: int orig_protect_args = protect_args;
1553:
1554: if (argc == 0) {
1555: strlcpy(err_buf, "argc is zero!\n", sizeof err_buf);
1556: return 0;
1557: }
1558:
1559: arg = *argv + strlen(*argv);
1560: if (arg - *argv > 2 && strcmp(arg-2, "db") == 0) {
1561: parse_dbonly_args(argc, argv);
1562: /* NOT REACHED */
1563: }
1564:
1565: set_refuse_options();
1566:
1567: #ifdef ICONV_OPTION
1568: if (!am_daemon && protect_args <= 0 && (arg = getenv("RSYNC_ICONV")) != NULL && *arg)
1569: iconv_opt = strdup(arg);
1570: #endif
1571:
1572: /* TODO: Call poptReadDefaultConfig; handle errors. */
1573:
1574: /* The context leaks in case of an error, but if there's a
1575: * problem we always exit anyhow. */
1576: if (pc)
1577: poptFreeContext(pc);
1578: pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0);
1579: if (!am_server) {
1580: poptReadDefaultConfig(pc, 0);
1581: popt_unalias(pc, "--daemon");
1582: popt_unalias(pc, "--server");
1583: }
1584:
1585: while ((opt = poptGetNextOpt(pc)) != -1) {
1586: /* most options are handled automatically by popt;
1587: * only special cases are returned and listed here. */
1588:
1589: switch (opt) {
1590: case 'V':
1591: version_opt_cnt++;
1592: break;
1593:
1594: case OPT_SERVER:
1595: if (!am_server) {
1596: /* Disable popt aliases on the server side and
1597: * then start parsing the options again. */
1598: poptFreeContext(pc);
1599: pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0);
1600: am_server = 1;
1601: }
1602: #ifdef ICONV_OPTION
1603: iconv_opt = NULL;
1604: #endif
1605: break;
1606:
1607: case OPT_SENDER:
1608: if (!am_server) {
1609: usage(FERROR);
1610: exit_cleanup(RERR_SYNTAX);
1611: }
1612: am_sender = 1;
1613: break;
1614:
1615: case OPT_DAEMON:
1616: if (am_daemon) {
1617: strlcpy(err_buf,
1618: "Attempt to hack rsync thwarted!\n",
1619: sizeof err_buf);
1620: return 0;
1621: }
1622: #ifdef ICONV_OPTION
1623: iconv_opt = NULL;
1624: #endif
1625: protect_args = 0;
1626: poptFreeContext(pc);
1627: pc = poptGetContext(RSYNC_NAME, argc, argv, long_daemon_options, 0);
1628: while ((opt = poptGetNextOpt(pc)) != -1) {
1629: char **cpp;
1630: switch (opt) {
1631: case 'h':
1632: daemon_usage(FINFO);
1633: exit_cleanup(0);
1634:
1635: case 'M':
1636: arg = poptGetOptArg(pc);
1637: if (!strchr(arg, '=')) {
1638: rprintf(FERROR,
1639: "--dparam value is missing an '=': %s\n",
1640: arg);
1641: goto daemon_error;
1642: }
1643: cpp = EXPAND_ITEM_LIST(&dparam_list, char *, 4);
1644: *cpp = strdup(arg);
1645: break;
1646:
1647: case 'v':
1648: verbose++;
1649: break;
1650:
1651: default:
1652: rprintf(FERROR,
1653: "rsync: %s: %s (in daemon mode)\n",
1654: poptBadOption(pc, POPT_BADOPTION_NOALIAS),
1655: poptStrerror(opt));
1656: goto daemon_error;
1657: }
1658: }
1659:
1660: if (dparam_list.count && !set_dparams(1))
1661: exit_cleanup(RERR_SYNTAX);
1662:
1663: if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
1664: snprintf(err_buf, sizeof err_buf,
1665: "the --temp-dir path is WAY too long.\n");
1666: return 0;
1667: }
1668:
1669: if (!daemon_opt) {
1670: rprintf(FERROR, "Daemon option(s) used without --daemon.\n");
1671: daemon_error:
1672: rprintf(FERROR, "(Type \"rsync --daemon --help\" for assistance with daemon mode.)\n");
1673: exit_cleanup(RERR_SYNTAX);
1674: }
1675:
1676: *argv_p = argv = poptGetArgs(pc);
1677: *argc_p = argc = count_args(argv);
1678: am_starting_up = 0;
1679: daemon_opt = 0;
1680: am_daemon = 1;
1681: return 1;
1682:
1683: case OPT_DBONLY:
1684: protect_args = 0;
1685: poptFreeContext(pc);
1686: parse_dbonly_args(argc, argv);
1687: break; /* NOT REACHED */
1688:
1689: case OPT_MODIFY_WINDOW:
1690: /* The value has already been set by popt, but
1691: * we need to remember that we're using a
1692: * non-default setting. */
1693: modify_window_set = 1;
1694: break;
1695:
1696: case OPT_FILTER:
1697: parse_filter_str(&filter_list, poptGetOptArg(pc),
1698: rule_template(0), 0);
1699: break;
1700:
1701: case OPT_EXCLUDE:
1702: parse_filter_str(&filter_list, poptGetOptArg(pc),
1703: rule_template(0), XFLG_OLD_PREFIXES);
1704: break;
1705:
1706: case OPT_INCLUDE:
1707: parse_filter_str(&filter_list, poptGetOptArg(pc),
1708: rule_template(FILTRULE_INCLUDE), XFLG_OLD_PREFIXES);
1709: break;
1710:
1711: case OPT_EXCLUDE_FROM:
1712: case OPT_INCLUDE_FROM:
1713: arg = poptGetOptArg(pc);
1714: if (sanitize_paths)
1715: arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT);
1716: if (daemon_filter_list.head) {
1717: int rej;
1718: char *cp = strdup(arg);
1719: if (!*cp)
1720: rej = 1;
1721: else {
1722: char *dir = cp + (*cp == '/' ? module_dirlen : 0);
1723: clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
1724: rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0;
1725: }
1726: free(cp);
1727: if (rej)
1728: goto options_rejected;
1729: }
1730: parse_filter_file(&filter_list, arg,
1731: rule_template(opt == OPT_INCLUDE_FROM ? FILTRULE_INCLUDE : 0),
1732: XFLG_FATAL_ERRORS | XFLG_OLD_PREFIXES);
1733: break;
1734:
1735: case 'a':
1736: if (refused_archive_part) {
1737: create_refuse_error(refused_archive_part);
1738: return 0;
1739: }
1740: if (!recurse) /* preserve recurse == 2 */
1741: recurse = 1;
1742: #ifdef SUPPORT_LINKS
1743: preserve_links = 1;
1744: #endif
1745: preserve_perms = 1;
1746: preserve_times = 1;
1747: preserve_gid = 1;
1748: preserve_uid = 1;
1749: preserve_devices = 1;
1750: preserve_specials = 1;
1751: break;
1752:
1753: case 'D':
1754: preserve_devices = preserve_specials = 1;
1755: break;
1756:
1757: case OPT_NO_D:
1758: preserve_devices = preserve_specials = 0;
1759: break;
1760:
1761: case OPT_NO_DB:
1762: db_config = NULL;
1763: break;
1764:
1765: case 'h':
1766: human_readable++;
1767: break;
1768:
1769: case 'H':
1770: preserve_hard_links++;
1771: break;
1772:
1773: case 'i':
1774: itemize_changes++;
1775: break;
1776:
1777: case 'U':
1778: if (++preserve_atimes > 1)
1779: open_noatime = 1;
1780: break;
1781:
1782: case 'v':
1783: verbose++;
1784: break;
1785:
1786: case 'y':
1787: fuzzy_basis++;
1788: break;
1789:
1790: case 'q':
1791: quiet++;
1792: break;
1793:
1794: case 'x':
1795: one_file_system++;
1796: break;
1797:
1798: case 'F':
1799: switch (++F_option_cnt) {
1800: case 1:
1801: parse_filter_str(&filter_list,": /.rsync-filter",rule_template(0),0);
1802: break;
1803: case 2:
1804: parse_filter_str(&filter_list,"- .rsync-filter",rule_template(0),0);
1805: break;
1806: }
1807: break;
1808:
1809: case 'P':
1810: if (refused_partial || refused_progress) {
1811: create_refuse_error(refused_partial ? refused_partial : refused_progress);
1812: return 0;
1813: }
1814: do_progress = 1;
1815: keep_partial = 1;
1816: break;
1817:
1818: case 'z':
1819: do_compression++;
1820: break;
1821:
1822: case OPT_OLD_COMPRESS:
1823: compress_choice = "zlib";
1824: break;
1825:
1826: case OPT_NEW_COMPRESS:
1827: compress_choice = "zlibx";
1828: break;
1829:
1830: case OPT_NO_COMPRESS:
1831: do_compression = 0;
1832: compress_choice = NULL;
1833: break;
1834:
1835: case 'M':
1836: arg = poptGetOptArg(pc);
1837: if (*arg != '-') {
1838: snprintf(err_buf, sizeof err_buf,
1839: "Remote option must start with a dash: %s\n", arg);
1840: return 0;
1841: }
1842: if (remote_option_cnt+2 >= remote_option_alloc) {
1843: remote_option_alloc += 16;
1844: remote_options = realloc_array(remote_options,
1845: const char *, remote_option_alloc);
1846: if (!remote_option_cnt)
1847: remote_options[0] = "ARG0";
1848: }
1849: remote_options[++remote_option_cnt] = arg;
1850: remote_options[remote_option_cnt+1] = NULL;
1851: break;
1852:
1853: case OPT_WRITE_BATCH:
1854: /* batch_name is already set */
1855: write_batch = 1;
1856: break;
1857:
1858: case OPT_ONLY_WRITE_BATCH:
1859: /* batch_name is already set */
1860: write_batch = -1;
1861: break;
1862:
1863: case OPT_READ_BATCH:
1864: /* batch_name is already set */
1865: read_batch = 1;
1866: break;
1867:
1868: case OPT_NO_ICONV:
1869: #ifdef ICONV_OPTION
1870: iconv_opt = NULL;
1871: #endif
1872: break;
1873:
1874: case OPT_BLOCK_SIZE: {
1875: /* We may not know the real protocol_version at this point if this is the client
1876: * option parsing, but we still want to check it so that the client can specify
1877: * a --protocol=29 option with a larger block size. */
1878: int max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE;
1879: ssize_t size;
1880: arg = poptGetOptArg(pc);
1881: if ((size = parse_size_arg(arg, 'b', "block-size", 0, max_blength, False)) < 0)
1882: return 0;
1883: block_size = (int32)size;
1884: break;
1885: }
1886:
1887: case OPT_MAX_SIZE:
1888: if ((max_size = parse_size_arg(max_size_arg, 'b', "max-size", 0, -1, False)) < 0)
1889: return 0;
1890: max_size_arg = strdup(do_big_num(max_size, 0, NULL));
1891: break;
1892:
1893: case OPT_MIN_SIZE:
1894: if ((min_size = parse_size_arg(min_size_arg, 'b', "min-size", 0, -1, False)) < 0)
1895: return 0;
1896: min_size_arg = strdup(do_big_num(min_size, 0, NULL));
1897: break;
1898:
1899: case OPT_BWLIMIT: {
1900: ssize_t size = parse_size_arg(bwlimit_arg, 'K', "bwlimit", 512, -1, True);
1901: if (size < 0)
1902: return 0;
1903: bwlimit_arg = strdup(do_big_num(size, 0, NULL));
1904: bwlimit = (size + 512) / 1024;
1905: break;
1906: }
1907:
1908: case OPT_APPEND:
1909: if (am_server)
1910: append_mode++;
1911: else
1912: append_mode = 1;
1913: break;
1914:
1915: case OPT_LINK_DEST:
1916: want_dest_type = LINK_DEST;
1917: goto set_dest_dir;
1918:
1919: case OPT_CLONE_DEST:
1920: want_dest_type = CLONE_DEST;
1921: goto set_dest_dir;
1922:
1923: case OPT_COPY_DEST:
1924: want_dest_type = COPY_DEST;
1925: goto set_dest_dir;
1926:
1927: case OPT_COMPARE_DEST:
1928: want_dest_type = COMPARE_DEST;
1929:
1930: set_dest_dir:
1931: if (alt_dest_type && alt_dest_type != want_dest_type) {
1932: snprintf(err_buf, sizeof err_buf,
1933: "ERROR: the %s option conflicts with the %s option\n",
1934: alt_dest_opt(want_dest_type), alt_dest_opt(0));
1935: return 0;
1936: }
1937: alt_dest_type = want_dest_type;
1938:
1939: if (basis_dir_cnt >= MAX_BASIS_DIRS) {
1940: snprintf(err_buf, sizeof err_buf,
1941: "ERROR: at most %d %s args may be specified\n",
1942: MAX_BASIS_DIRS, alt_dest_opt(0));
1943: return 0;
1944: }
1945: /* We defer sanitizing this arg until we know what
1946: * our destination directory is going to be. */
1947: basis_dir[basis_dir_cnt++] = (char *)poptGetOptArg(pc);
1948: break;
1949:
1950: case OPT_CHMOD:
1951: arg = poptGetOptArg(pc);
1952: if (!parse_chmod(arg, &chmod_modes)) {
1953: snprintf(err_buf, sizeof err_buf,
1954: "Invalid argument passed to --chmod (%s)\n",
1955: arg);
1956: return 0;
1957: }
1958: break;
1959:
1960: case OPT_SUMFILES:
1961: arg = poptGetOptArg(pc);
1962: if (*arg == '+') {
1963: arg++;
1964: checksum_files = CSF_UPDATE;
1965: if (*arg == '+') {
1966: arg++;
1967: checksum_files |= CSF_AFFECT_DRYRUN;
1968: }
1969: } else
1970: checksum_files = 0;
1971: if (strcmp(arg, "lax") == 0)
1972: checksum_files |= CSF_LAX_MODE;
1973: else if (strcmp(arg, "strict") == 0)
1974: checksum_files |= CSF_STRICT_MODE;
1975: else if (strcmp(arg, "none") == 0)
1976: checksum_files = CSF_IGNORE_FILES;
1977: else {
1978: snprintf(err_buf, sizeof err_buf,
1979: "Invalid argument passed to --sumfiles (%s)\n",
1980: arg);
1981: return 0;
1982: }
1983: break;
1984:
1985: case OPT_INFO:
1986: arg = poptGetOptArg(pc);
1987: parse_output_words(info_words, info_levels, arg, USER_PRIORITY);
1988: break;
1989:
1990: case OPT_DEBUG:
1991: arg = poptGetOptArg(pc);
1992: parse_output_words(debug_words, debug_levels, arg, USER_PRIORITY);
1993: break;
1994:
1995: case OPT_USERMAP:
1996: if (usermap) {
1997: if (usermap_via_chown) {
1998: snprintf(err_buf, sizeof err_buf,
1999: "--usermap conflicts with prior --chown.\n");
2000: return 0;
2001: }
2002: snprintf(err_buf, sizeof err_buf,
2003: "You can only specify --usermap once.\n");
2004: return 0;
2005: }
2006: usermap = (char *)poptGetOptArg(pc);
2007: usermap_via_chown = False;
2008: break;
2009:
2010: case OPT_GROUPMAP:
2011: if (groupmap) {
2012: if (groupmap_via_chown) {
2013: snprintf(err_buf, sizeof err_buf,
2014: "--groupmap conflicts with prior --chown.\n");
2015: return 0;
2016: }
2017: snprintf(err_buf, sizeof err_buf,
2018: "You can only specify --groupmap once.\n");
2019: return 0;
2020: }
2021: groupmap = (char *)poptGetOptArg(pc);
2022: groupmap_via_chown = False;
2023: break;
2024:
2025: case OPT_CHOWN: {
2026: const char *chown = poptGetOptArg(pc);
2027: int len;
2028: if ((arg = strchr(chown, ':')) != NULL)
2029: len = arg++ - chown;
2030: else
2031: len = strlen(chown);
2032: if (len) {
2033: if (usermap) {
2034: if (!usermap_via_chown) {
2035: snprintf(err_buf, sizeof err_buf,
2036: "--chown conflicts with prior --usermap.\n");
2037: return 0;
2038: }
2039: snprintf(err_buf, sizeof err_buf,
2040: "You can only specify a user-affecting --chown once.\n");
2041: return 0;
2042: }
2043: if (asprintf(&usermap, "*:%.*s", len, chown) < 0)
2044: out_of_memory("parse_arguments");
2045: usermap_via_chown = True;
2046: }
2047: if (arg && *arg) {
2048: if (groupmap) {
2049: if (!groupmap_via_chown) {
2050: snprintf(err_buf, sizeof err_buf,
2051: "--chown conflicts with prior --groupmap.\n");
2052: return 0;
2053: }
2054: snprintf(err_buf, sizeof err_buf,
2055: "You can only specify a group-affecting --chown once.\n");
2056: return 0;
2057: }
2058: if (asprintf(&groupmap, "*:%s", arg) < 0)
2059: out_of_memory("parse_arguments");
2060: groupmap_via_chown = True;
2061: }
2062: break;
2063: }
2064:
2065: case OPT_HELP:
2066: usage(FINFO);
2067: exit_cleanup(0);
2068:
2069: case 'A':
2070: #ifdef SUPPORT_ACLS
2071: preserve_acls = 1;
2072: preserve_perms = 1;
2073: break;
2074: #else
2075: /* FIXME: this should probably be ignored with a
2076: * warning and then countermeasures taken to
2077: * restrict group and other access in the presence
2078: * of any more restrictive ACLs, but this is safe
2079: * for now */
2080: snprintf(err_buf,sizeof(err_buf),
2081: "ACLs are not supported on this %s\n",
2082: am_server ? "server" : "client");
2083: return 0;
2084: #endif
2085:
2086: case 'X':
2087: #ifdef SUPPORT_XATTRS
2088: preserve_xattrs++;
2089: break;
2090: #else
2091: snprintf(err_buf,sizeof(err_buf),
2092: "extended attributes are not supported on this %s\n",
2093: am_server ? "server" : "client");
2094: return 0;
2095: #endif
2096:
2097: case OPT_LINK_BY_HASH:
2098: #ifdef HAVE_LINK
2099: arg = poptGetOptArg(pc);
2100: if (sanitize_paths)
2101: arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT);
2102: link_by_hash_dir = (char *)arg;
2103: break;
2104: #else
2105: snprintf(err_buf, sizeof err_buf,
2106: "hard links are not supported on this %s\n",
2107: am_server ? "server" : "client");
2108: return 0;
2109: #endif
2110:
2111: case OPT_STOP_AFTER: {
2112: long val;
2113: arg = poptGetOptArg(pc);
2114: stop_at_utime = time(NULL);
2115: if ((val = atol(arg) * 60) <= 0 || LONG_MAX - val < stop_at_utime || (long)(time_t)val != val) {
2116: snprintf(err_buf, sizeof err_buf, "invalid --stop-after value: %s\n", arg);
2117: return 0;
2118: }
2119: stop_at_utime += val;
2120: break;
2121: }
2122:
2123: #ifdef HAVE_MKTIME
2124: case OPT_STOP_AT:
2125: arg = poptGetOptArg(pc);
2126: if ((stop_at_utime = parse_time(arg)) == (time_t)-1) {
2127: snprintf(err_buf, sizeof err_buf, "invalid --stop-at format: %s\n", arg);
2128: return 0;
2129: }
2130: if (stop_at_utime <= time(NULL)) {
2131: snprintf(err_buf, sizeof err_buf, "--stop-at time is not in the future: %s\n", arg);
2132: return 0;
2133: }
2134: break;
2135: #endif
2136:
2137: case OPT_STDERR: {
2138: int len;
2139: arg = poptGetOptArg(pc);
2140: len = strlen(arg);
2141: if (len && strncmp("errors", arg, len) == 0)
2142: msgs2stderr = 2;
2143: else if (len && strncmp("all", arg, len) == 0)
2144: msgs2stderr = 1;
2145: else if (len && strncmp("client", arg, len) == 0)
2146: msgs2stderr = 0;
2147: else {
2148: snprintf(err_buf, sizeof err_buf,
2149: "--stderr mode \"%s\" is not one of errors, all, or client\n", arg);
2150: return 0;
2151: }
2152: break;
2153: }
2154:
2155: default:
2156: /* A large opt value means that set_refuse_options()
2157: * turned this option off. */
2158: if (opt >= OPT_REFUSED_BASE) {
2159: create_refuse_error(opt);
2160: return 0;
2161: }
2162: snprintf(err_buf, sizeof err_buf, "%s%s: %s\n",
2163: am_server ? "on remote machine: " : "",
2164: poptBadOption(pc, POPT_BADOPTION_NOALIAS),
2165: poptStrerror(opt));
2166: return 0;
2167: }
2168: }
2169:
2170: if (version_opt_cnt) {
2171: print_rsync_version(FINFO);
2172: exit_cleanup(0);
2173: }
2174:
2175: if (!max_alloc_arg) {
2176: max_alloc_arg = getenv("RSYNC_MAX_ALLOC");
2177: if (max_alloc_arg && !*max_alloc_arg)
2178: max_alloc_arg = NULL;
2179: }
2180: if (max_alloc_arg) {
2181: ssize_t size = parse_size_arg(max_alloc_arg, 'B', "max-alloc", 1024*1024, -1, True);
2182: if (size < 0)
2183: return 0;
2184: max_alloc = size;
2185: }
2186:
2187: if (protect_args < 0) {
2188: if (am_server)
2189: protect_args = 0;
2190: else if ((arg = getenv("RSYNC_PROTECT_ARGS")) != NULL && *arg)
2191: protect_args = atoi(arg) ? 1 : 0;
2192: else {
2193: #ifdef RSYNC_USE_PROTECTED_ARGS
2194: protect_args = 1;
2195: #else
2196: protect_args = 0;
2197: #endif
2198: }
2199: }
2200:
2201: if (checksum_choice && strcasecmp(checksum_choice, "auto") != 0 && strcasecmp(checksum_choice, "auto,auto") != 0) {
2202: /* Call this early to verify the args and figure out if we need to force
2203: * --whole-file. Note that the parse function will get called again later,
2204: * just in case an "auto" choice needs to know the protocol_version. */
2205: parse_checksum_choice(0);
2206: } else
2207: checksum_choice = NULL;
2208:
2209: if (human_readable > 1 && argc == 2 && !am_server) {
2210: /* Allow the old meaning of 'h' (--help) on its own. */
2211: usage(FINFO);
2212: exit_cleanup(0);
2213: }
2214:
2215: if (!compress_choice && do_compression > 1)
2216: compress_choice = "zlibx";
2217: if (compress_choice && strcasecmp(compress_choice, "auto") != 0)
2218: parse_compress_choice(0); /* Twiddles do_compression and can possibly NULL-out compress_choice. */
2219: else
2220: compress_choice = NULL;
2221:
2222: if (do_compression || do_compression_level != CLVL_NOT_SPECIFIED) {
2223: if (!do_compression)
2224: do_compression = CPRES_AUTO;
2225: if (do_compression && refused_compress) {
2226: create_refuse_error(refused_compress);
2227: return 0;
2228: }
2229: }
2230:
2231: #ifdef HAVE_SETVBUF
2232: if (outbuf_mode && !am_server) {
2233: int mode = *(uchar *)outbuf_mode;
2234: if (islower(mode))
2235: mode = toupper(mode);
2236: fflush(stdout); /* Just in case... */
2237: switch (mode) {
2238: case 'N': /* None */
2239: case 'U': /* Unbuffered */
2240: mode = _IONBF;
2241: break;
2242: case 'L': /* Line */
2243: mode = _IOLBF;
2244: break;
2245: case 'B': /* Block */
2246: case 'F': /* Full */
2247: mode = _IOFBF;
2248: break;
2249: default:
2250: snprintf(err_buf, sizeof err_buf,
2251: "Invalid --outbuf setting -- specify N, L, or B.\n");
2252: return 0;
2253: }
2254: setvbuf(stdout, (char *)NULL, mode, 0);
2255: }
2256:
2257: if (msgs2stderr == 1) { /* Are all messages going to stderr? */
2258: /* Make stderr line buffered for better sharing of the stream. */
2259: fflush(stderr); /* Just in case... */
2260: setvbuf(stderr, (char *)NULL, _IOLBF, 0);
2261: }
2262: #endif
2263:
2264: set_output_verbosity(verbose, DEFAULT_PRIORITY);
2265:
2266: if (do_stats) {
2267: parse_output_words(info_words, info_levels,
2268: verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY);
2269: }
2270:
2271: #ifdef ICONV_OPTION
2272: if (iconv_opt && protect_args != 2) {
2273: if (!am_server && strcmp(iconv_opt, "-") == 0)
2274: iconv_opt = NULL;
2275: else
2276: need_unsorted_flist = 1;
2277: }
2278: if (refused_no_iconv && !iconv_opt) {
2279: create_refuse_error(refused_no_iconv);
2280: return 0;
2281: }
2282: #endif
2283:
2284: if (fuzzy_basis > 1)
2285: fuzzy_basis = basis_dir_cnt + 1;
2286:
2287: /* Don't let the client reset protect_args if it was already processed */
2288: if (orig_protect_args == 2 && am_server)
2289: protect_args = orig_protect_args;
2290:
2291: if (protect_args == 1 && am_server)
2292: return 1;
2293:
2294: *argv_p = argv = poptGetArgs(pc);
2295: *argc_p = argc = count_args(argv);
2296:
2297: #ifndef SUPPORT_LINKS
2298: if (preserve_links && !am_sender) {
2299: snprintf(err_buf, sizeof err_buf,
2300: "symlinks are not supported on this %s\n",
2301: am_server ? "server" : "client");
2302: return 0;
2303: }
2304: #endif
2305:
2306: #ifndef SUPPORT_HARD_LINKS
2307: if (preserve_hard_links) {
2308: snprintf(err_buf, sizeof err_buf,
2309: "hard links are not supported on this %s\n",
2310: am_server ? "server" : "client");
2311: return 0;
2312: }
2313: #endif
2314:
2315: #ifdef SUPPORT_XATTRS
2316: if (am_root < 0 && preserve_xattrs > 1) {
2317: snprintf(err_buf, sizeof err_buf,
2318: "--fake-super conflicts with -XX\n");
2319: return 0;
2320: }
2321: #else
2322: if (am_root < 0) {
2323: snprintf(err_buf, sizeof err_buf,
2324: "--fake-super requires an rsync with extended attributes enabled\n");
2325: return 0;
2326: }
2327: #endif
2328:
2329: if (!always_checksum)
2330: checksum_files = CSF_IGNORE_FILES;
2331:
2332: #ifdef SUPPORT_HFS_COMPRESSION
2333: if (preserve_hfs_compression) {
2334: if (!preserve_xattrs)
2335: preserve_xattrs = 1;
2336: if (!preserve_fileflags)
2337: preserve_fileflags = 1;
2338: }
2339: #endif
2340:
2341: if (write_batch && read_batch) {
2342: snprintf(err_buf, sizeof err_buf,
2343: "--write-batch and --read-batch can not be used together\n");
2344: return 0;
2345: }
2346: if (write_batch > 0 || read_batch) {
2347: if (am_server) {
2348: rprintf(FINFO,
2349: "ignoring --%s-batch option sent to server\n",
2350: write_batch ? "write" : "read");
2351: /* We don't actually exit_cleanup(), so that we can
2352: * still service older version clients that still send
2353: * batch args to server. */
2354: read_batch = write_batch = 0;
2355: batch_name = NULL;
2356: } else if (dry_run)
2357: write_batch = 0;
2358: } else if (write_batch < 0 && dry_run)
2359: write_batch = 0;
2360: if (read_batch && files_from) {
2361: snprintf(err_buf, sizeof err_buf,
2362: "--read-batch cannot be used with --files-from\n");
2363: return 0;
2364: }
2365: if (read_batch && remove_source_files) {
2366: snprintf(err_buf, sizeof err_buf,
2367: "--read-batch cannot be used with --remove-%s-files\n",
2368: remove_source_files == 1 ? "source" : "sent");
2369: return 0;
2370: }
2371: if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
2372: snprintf(err_buf, sizeof err_buf,
2373: "the batch-file name must be %d characters or less.\n",
2374: MAX_BATCH_NAME_LEN);
2375: return 0;
2376: }
2377:
2378: if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
2379: snprintf(err_buf, sizeof err_buf,
2380: "the --temp-dir path is WAY too long.\n");
2381: return 0;
2382: }
2383:
2384: if (max_delete < 0 && max_delete != INT_MIN) {
2385: /* Negative numbers are treated as "no deletions". */
2386: max_delete = 0;
2387: }
2388:
2389: if (files_from) {
2390: if (recurse == 1) /* preserve recurse == 2 */
2391: recurse = 0;
2392: if (xfer_dirs < 0)
2393: xfer_dirs = 1;
2394: }
2395:
2396: if (argc < 2 && !read_batch && !am_server)
2397: list_only |= 1;
2398:
2399: if (xfer_dirs >= 4) {
2400: parse_filter_str(&filter_list, "- /*/*", rule_template(0), 0);
2401: recurse = xfer_dirs = 1;
2402: } else if (recurse)
2403: xfer_dirs = 1;
2404: else if (xfer_dirs < 0)
2405: xfer_dirs = list_only ? 1 : 0;
2406:
2407: if (relative_paths < 0)
2408: relative_paths = files_from? 1 : 0;
2409: if (!relative_paths)
2410: implied_dirs = 0;
2411:
2412: if (delete_before + !!delete_during + delete_after > 1) {
2413: snprintf(err_buf, sizeof err_buf,
2414: "You may not combine multiple --delete-WHEN options.\n");
2415: return 0;
2416: }
2417: if (delete_before || delete_during || delete_after)
2418: delete_mode = 1;
2419: else if (delete_mode || delete_excluded) {
2420: /* Only choose now between before & during if one is refused. */
2421: if (refused_delete_before) {
2422: if (!refused_delete_during)
2423: delete_during = 1;
2424: else {
2425: create_refuse_error(refused_delete_before);
2426: return 0;
2427: }
2428: } else if (refused_delete_during)
2429: delete_before = 1;
2430: delete_mode = 1;
2431: }
2432: if (!xfer_dirs && delete_mode) {
2433: snprintf(err_buf, sizeof err_buf,
2434: "--delete does not work without --recursive (-r) or --dirs (-d).\n");
2435: return 0;
2436: }
2437:
2438: if (missing_args == 3) /* simplify if both options were specified */
2439: missing_args = 2;
2440: if (refused_delete && (delete_mode || missing_args == 2)) {
2441: create_refuse_error(refused_delete);
2442: return 0;
2443: }
2444:
2445: if (remove_source_files) {
2446: /* We only want to infer this refusal of --remove-source-files
2447: * via the refusal of "delete", not any of the "delete-FOO"
2448: * options. */
2449: if (refused_delete && am_sender) {
2450: create_refuse_error(refused_delete);
2451: return 0;
2452: }
2453: need_messages_from_generator = 1;
2454: }
2455:
2456: if (munge_symlinks && !am_daemon) {
2457: STRUCT_STAT st;
2458: char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
2459: strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
2460: if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
2461: rprintf(FERROR, "Symlink munging is unsafe when a %s directory exists.\n",
2462: prefix);
2463: exit_cleanup(RERR_UNSUPPORTED);
2464: }
2465: }
2466:
2467: if (sanitize_paths) {
2468: int i;
2469: for (i = argc; i-- > 0; )
2470: argv[i] = sanitize_path(NULL, argv[i], "", 0, SP_KEEP_DOT_DIRS);
2471: if (tmpdir)
2472: tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT);
2473: if (backup_dir)
2474: backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT);
2475: if (backup_dir_dels)
2476: backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0, SP_DEFAULT);
2477: }
2478: if (daemon_filter_list.head && !am_sender) {
2479: filter_rule_list *elp = &daemon_filter_list;
2480: if (tmpdir) {
2481: char *dir;
2482: if (!*tmpdir)
2483: goto options_rejected;
2484: dir = tmpdir + (*tmpdir == '/' ? module_dirlen : 0);
2485: clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
2486: if (check_filter(elp, FLOG, dir, 1) < 0)
2487: goto options_rejected;
2488: }
2489: if (backup_dir) {
2490: char *dir;
2491: if (!*backup_dir)
2492: goto options_rejected;
2493: dir = backup_dir + (*backup_dir == '/' ? module_dirlen : 0);
2494: clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
2495: if (check_filter(elp, FLOG, dir, 1) < 0)
2496: goto options_rejected;
2497: }
2498: /* Clean backup_dir_dels same as for backup_dir */
2499: if (backup_dir_dels) {
2500: if (!*backup_dir_dels)
2501: goto options_rejected;
2502: clean_fname(backup_dir_dels, 1);
2503: if (check_filter(elp, FLOG, backup_dir_dels, 1) < 0)
2504: goto options_rejected;
2505: }
2506: }
2507:
2508: if (!backup_suffix)
2509: backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
2510: backup_suffix_len = strlen(backup_suffix);
2511: if (strchr(backup_suffix, '/') != NULL) {
2512: snprintf(err_buf, sizeof err_buf,
2513: "--suffix cannot contain slashes: %s\n",
2514: backup_suffix);
2515: return 0;
2516: }
2517: /* --suffix-dels defaults to --suffix, or empty for a client given an
2518: * explicit --backup-dir-dels (just as --suffix defaults to empty when
2519: * a --backup-dir is given). The second case does not apply to the
2520: * server for consistency with server_options, which sends --suffix-dels
2521: * to the server iff it differs from --suffix. */
2522: if (!backup_suffix_dels)
2523: backup_suffix_dels = backup_dir_dels && !am_server ? "" : backup_suffix;
2524: backup_suffix_dels_len = strlen(backup_suffix_dels);
2525: if (strchr(backup_suffix_dels, '/') != NULL) {
2526: snprintf(err_buf, sizeof err_buf,
2527: "--suffix-dels cannot contain slashes: %s\n",
2528: backup_suffix_dels);
2529: return 0;
2530: }
2531: if (backup_dir) {
2532: size_t len;
2533: make_backups = 1; /* --backup-dir implies --backup */
2534: while (*backup_dir == '.' && backup_dir[1] == '/')
2535: backup_dir += 2;
2536: if (*backup_dir == '.' && backup_dir[1] == '\0')
2537: backup_dir++;
2538: len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
2539: if (len > sizeof backup_dir_buf - 128) {
2540: snprintf(err_buf, sizeof err_buf,
2541: "the --backup-dir path is WAY too long.\n");
2542: return 0;
2543: }
2544: backup_dir_len = (int)len;
2545: if (!backup_dir_len) {
2546: backup_dir_len = -1;
2547: backup_dir = NULL;
2548: } else if (backup_dir_buf[backup_dir_len - 1] != '/') {
2549: backup_dir_buf[backup_dir_len++] = '/';
2550: backup_dir_buf[backup_dir_len] = '\0';
2551: }
2552: backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
2553: }
2554: if (backup_dir) {
2555: /* No need for a suffix or a protect rule. */
2556: } else if (!backup_suffix_len && (!am_server || !am_sender)) {
2557: snprintf(err_buf, sizeof err_buf,
2558: "--suffix cannot be empty %s\n", backup_dir_len < 0
2559: ? "when --backup-dir is the same as the dest dir"
2560: : "without a --backup-dir");
2561: return 0;
2562: } else if (make_backups && delete_mode && !delete_excluded && !am_server) {
2563: snprintf(backup_dir_buf, sizeof backup_dir_buf,
2564: "P *%s", backup_suffix);
2565: parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0);
2566: }
2567: if (backup_dir_dels) {
2568: backup_dir_dels_len = strlcpy(backup_dir_dels_buf, backup_dir_dels, sizeof backup_dir_dels_buf);
2569: backup_dir_dels_remainder = sizeof backup_dir_dels_buf - backup_dir_dels_len;
2570: if (backup_dir_dels_remainder < 32) {
2571: snprintf(err_buf, sizeof err_buf,
2572: "the --backup-dir-dels path is WAY too long.\n");
2573: return 0;
2574: }
2575: if (backup_dir_dels_buf[backup_dir_dels_len - 1] != '/') {
2576: backup_dir_dels_buf[backup_dir_dels_len++] = '/';
2577: backup_dir_dels_buf[backup_dir_dels_len] = '\0';
2578: }
2579: if (INFO_GTE(BACKUP, 1) && !am_sender)
2580: rprintf(FINFO, "backup_dir_dels is %s\n", backup_dir_dels_buf);
2581: } else if (backup_dir) {
2582: backup_dir_dels = backup_dir;
2583: backup_dir_dels_len = backup_dir_len;
2584: backup_dir_dels_remainder = backup_dir_remainder;
2585: strlcpy(backup_dir_dels_buf, backup_dir_buf, sizeof backup_dir_buf);
2586: } else if (!backup_suffix_dels_len && (!am_server || !am_sender)) {
2587: snprintf(err_buf, sizeof err_buf,
2588: "--suffix-dels cannot be a null string without --backup-dir-dels\n");
2589: return 0;
2590: } else if (make_backups && delete_mode && !delete_excluded && !am_server) {
2591: snprintf(backup_dir_dels_buf, sizeof backup_dir_dels_buf,
2592: "P *%s", backup_suffix_dels);
2593: parse_filter_str(&filter_list, backup_dir_dels_buf, rule_template(0), 0);
2594: }
2595:
2596: if (omit_dir_changes)
2597: omit_dir_times = 1;
2598:
2599: if (preserve_times) {
2600: preserve_times = PRESERVE_FILE_TIMES;
2601: if (!omit_dir_times)
2602: preserve_times |= PRESERVE_DIR_TIMES;
2603: #ifdef CAN_SET_SYMLINK_TIMES
2604: if (!omit_link_times)
2605: preserve_times |= PRESERVE_LINK_TIMES;
2606: #endif
2607: }
2608:
2609: if (make_backups && !backup_dir) {
2610: omit_dir_times = 0; /* Implied, so avoid -O to sender. */
2611: preserve_times &= ~PRESERVE_DIR_TIMES;
2612: }
2613:
2614: if (stdout_format) {
2615: if (am_server && log_format_has(stdout_format, 'I'))
2616: stdout_format_has_i = 2;
2617: else if (log_format_has(stdout_format, 'i'))
2618: stdout_format_has_i = itemize_changes | 1;
2619: if (!log_format_has(stdout_format, 'b')
2620: && !log_format_has(stdout_format, 'c')
2621: && !log_format_has(stdout_format, 'C'))
2622: log_before_transfer = !am_server;
2623: } else if (itemize_changes) {
2624: stdout_format = "%i %n%L";
2625: stdout_format_has_i = itemize_changes;
2626: log_before_transfer = !am_server;
2627: }
2628:
2629: if (do_progress && !am_server) {
2630: if (!log_before_transfer && INFO_EQ(NAME, 0))
2631: parse_output_words(info_words, info_levels, "name", DEFAULT_PRIORITY);
2632: parse_output_words(info_words, info_levels, "flist2,progress", DEFAULT_PRIORITY);
2633: }
2634:
2635: if (dry_run)
2636: do_xfers = 0;
2637:
2638: set_io_timeout(io_timeout);
2639:
2640: if (INFO_GTE(NAME, 1) && !stdout_format) {
2641: stdout_format = "%n%L";
2642: log_before_transfer = !am_server;
2643: }
2644: if (stdout_format_has_i || log_format_has(stdout_format, 'o'))
2645: stdout_format_has_o_or_i = 1;
2646:
2647: if (logfile_name && !am_daemon) {
2648: if (!logfile_format) {
2649: logfile_format = "%i %n%L";
2650: logfile_format_has_i = logfile_format_has_o_or_i = 1;
2651: } else {
2652: if (log_format_has(logfile_format, 'i'))
2653: logfile_format_has_i = 1;
2654: if (logfile_format_has_i || log_format_has(logfile_format, 'o'))
2655: logfile_format_has_o_or_i = 1;
2656: }
2657: log_init(0);
2658: } else if (!am_daemon)
2659: logfile_format = NULL;
2660:
2661: if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit))
2662: bwlimit = daemon_bwlimit;
2663: if (bwlimit) {
2664: bwlimit_writemax = (size_t)bwlimit * 128;
2665: if (bwlimit_writemax < 512)
2666: bwlimit_writemax = 512;
2667: }
2668:
2669: if (append_mode) {
2670: if (whole_file > 0) {
2671: snprintf(err_buf, sizeof err_buf,
2672: "--append cannot be used with --whole-file\n");
2673: return 0;
2674: }
2675: if (refused_inplace) {
2676: create_refuse_error(refused_inplace);
2677: return 0;
2678: }
2679: inplace = 1;
2680: }
2681:
2682: if (write_devices) {
2683: if (refused_inplace) {
2684: create_refuse_error(refused_inplace);
2685: return 0;
2686: }
2687: inplace = 1;
2688: }
2689:
2690: if ((delay_updates || detect_renamed) && !partial_dir)
2691: partial_dir = tmp_partialdir;
2692:
2693: if (inplace) {
2694: #ifdef HAVE_FTRUNCATE
2695: if (partial_dir) {
2696: snprintf(err_buf, sizeof err_buf,
2697: "--%s cannot be used with --%s\n",
2698: append_mode ? "append" : "inplace",
2699: detect_renamed ? "detect-renamed" :
2700: delay_updates ? "delay-updates" : "partial-dir");
2701: return 0;
2702: }
2703: /* --inplace implies --partial for refusal purposes, but we
2704: * clear the keep_partial flag for internal logic purposes. */
2705: if (refused_partial) {
2706: create_refuse_error(refused_partial);
2707: return 0;
2708: }
2709: keep_partial = 0;
2710: #else
2711: snprintf(err_buf, sizeof err_buf,
2712: "--%s is not supported on this %s\n",
2713: append_mode ? "append" : "inplace",
2714: am_server ? "server" : "client");
2715: return 0;
2716: #endif
2717: } else {
2718: if (keep_partial && !partial_dir && !am_server) {
2719: if ((arg = getenv("RSYNC_PARTIAL_DIR")) != NULL && *arg)
2720: partial_dir = strdup(arg);
2721: }
2722: if (partial_dir) {
2723: if (*partial_dir)
2724: clean_fname(partial_dir, CFN_COLLAPSE_DOT_DOT_DIRS);
2725: if (!*partial_dir || strcmp(partial_dir, ".") == 0)
2726: partial_dir = NULL;
2727: if (!partial_dir && refused_partial) {
2728: create_refuse_error(refused_partial);
2729: return 0;
2730: }
2731: keep_partial = 1;
2732: }
2733: }
2734:
2735: if (source_filter || dest_filter) {
2736: if (whole_file == 0) {
2737: snprintf(err_buf, sizeof err_buf,
2738: "--no-whole-file cannot be used with --%s-filter\n",
2739: source_filter ? "source" : "dest");
2740: return 0;
2741: }
2742: whole_file = 1;
2743: }
2744:
2745: if (files_from) {
2746: char *h, *p;
2747: int q;
2748: if (argc > 2 || (!am_daemon && !am_server && argc == 1)) {
2749: usage(FERROR);
2750: exit_cleanup(RERR_SYNTAX);
2751: }
2752: if (strcmp(files_from, "-") == 0) {
2753: filesfrom_fd = 0;
2754: if (am_server)
2755: filesfrom_host = ""; /* reading from socket */
2756: } else if ((p = check_for_hostspec(files_from, &h, &q)) != 0) {
2757: if (am_server) {
2758: snprintf(err_buf, sizeof err_buf,
2759: "The --files-from sent to the server cannot specify a host.\n");
2760: return 0;
2761: }
2762: files_from = p;
2763: filesfrom_host = h;
2764: if (strcmp(files_from, "-") == 0) {
2765: snprintf(err_buf, sizeof err_buf,
2766: "Invalid --files-from remote filename\n");
2767: return 0;
2768: }
2769: } else {
2770: if (sanitize_paths)
2771: files_from = sanitize_path(NULL, files_from, NULL, 0, SP_DEFAULT);
2772: if (daemon_filter_list.head) {
2773: char *dir;
2774: if (!*files_from)
2775: goto options_rejected;
2776: dir = files_from + (*files_from == '/' ? module_dirlen : 0);
2777: clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
2778: if (check_filter(&daemon_filter_list, FLOG, dir, 0) < 0)
2779: goto options_rejected;
2780: }
2781: filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
2782: if (filesfrom_fd < 0) {
2783: snprintf(err_buf, sizeof err_buf,
2784: "failed to open files-from file %s: %s\n",
2785: files_from, strerror(errno));
2786: return 0;
2787: }
2788: }
2789: }
2790:
2791: if (tr_opt) {
2792: if (*tr_opt == '/' && tr_opt[1]) {
2793: snprintf(err_buf, sizeof err_buf,
2794: "Do not start the --tr arg with a slash\n");
2795: return 0;
2796: }
2797: if (*tr_opt && *tr_opt != '/') {
2798: need_unsorted_flist = 1;
2799: arg = strchr(tr_opt, '/');
2800: if (arg && strchr(arg+1, '/')) {
2801: snprintf(err_buf, sizeof err_buf,
2802: "--tr cannot transliterate slashes\n");
2803: return 0;
2804: }
2805: } else
2806: tr_opt = NULL;
2807: }
2808:
2809: am_starting_up = 0;
2810:
2811: return 1;
2812:
2813: options_rejected:
2814: snprintf(err_buf, sizeof err_buf,
2815: "Your options have been rejected by the server.\n");
2816: return 0;
2817: }
2818:
2819:
2820: /**
2821: * Construct a filtered list of options to pass through from the
2822: * client to the server.
2823: *
2824: * This involves setting options that will tell the server how to
2825: * behave, and also filtering out options that are processed only
2826: * locally.
2827: **/
2828: void server_options(char **args, int *argc_p)
2829: {
2830: static char argstr[64];
2831: int ac = *argc_p;
2832: uchar where;
2833: char *arg;
2834: int i, x;
2835:
2836: /* This should always remain first on the server's command-line. */
2837: args[ac++] = "--server";
2838:
2839: if (!am_sender)
2840: args[ac++] = "--sender";
2841:
2842: x = 1;
2843: argstr[0] = '-';
2844:
2845: if (protect_args)
2846: argstr[x++] = 's';
2847:
2848: for (i = 0; i < verbose; i++)
2849: argstr[x++] = 'v';
2850:
2851: if (quiet && msgs2stderr)
2852: argstr[x++] = 'q';
2853: if (make_backups)
2854: argstr[x++] = 'b';
2855: if (update_only)
2856: argstr[x++] = 'u';
2857: if (!do_xfers) /* Note: NOT "dry_run"! */
2858: argstr[x++] = 'n';
2859: if (preserve_links)
2860: argstr[x++] = 'l';
2861: if ((xfer_dirs >= 2 && xfer_dirs < 4)
2862: || (xfer_dirs && !recurse && (list_only || (delete_mode && am_sender))))
2863: argstr[x++] = 'd';
2864: if (am_sender) {
2865: if (keep_dirlinks)
2866: argstr[x++] = 'K';
2867: if (prune_empty_dirs)
2868: argstr[x++] = 'm';
2869: if (omit_dir_times)
2870: argstr[x++] = 'O';
2871: if (omit_link_times)
2872: argstr[x++] = 'J';
2873: if (omit_dir_changes == 1)
2874: args[ac++] = "--omit-dir-changes";
2875: if (fuzzy_basis) {
2876: argstr[x++] = 'y';
2877: if (fuzzy_basis > 1)
2878: argstr[x++] = 'y';
2879: }
2880: } else {
2881: if (copy_links)
2882: argstr[x++] = 'L';
2883: if (copy_dirlinks)
2884: argstr[x++] = 'k';
2885: }
2886:
2887: if (whole_file > 0)
2888: argstr[x++] = 'W';
2889: /* We don't need to send --no-whole-file, because it's the
2890: * default for remote transfers, and in any case old versions
2891: * of rsync will not understand it. */
2892:
2893: if (preserve_hard_links) {
2894: argstr[x++] = 'H';
2895: if (preserve_hard_links > 1)
2896: argstr[x++] = 'H';
2897: }
2898: if (preserve_uid)
2899: argstr[x++] = 'o';
2900: if (preserve_gid)
2901: argstr[x++] = 'g';
2902: if (preserve_devices) /* ignore preserve_specials here */
2903: argstr[x++] = 'D';
2904: if (preserve_times)
2905: argstr[x++] = 't';
2906: if (preserve_atimes) {
2907: argstr[x++] = 'U';
2908: if (preserve_atimes > 1)
2909: argstr[x++] = 'U';
2910: }
2911: #ifdef SUPPORT_CRTIMES
2912: if (preserve_crtimes)
2913: argstr[x++] = 'N';
2914: #endif
2915: if (preserve_perms)
2916: argstr[x++] = 'p';
2917: else if (preserve_executability && am_sender)
2918: argstr[x++] = 'E';
2919: #ifdef SUPPORT_ACLS
2920: if (preserve_acls)
2921: argstr[x++] = 'A';
2922: #endif
2923: #ifdef SUPPORT_XATTRS
2924: if (preserve_xattrs) {
2925: argstr[x++] = 'X';
2926: if (preserve_xattrs > 1)
2927: argstr[x++] = 'X';
2928: }
2929: #endif
2930: if (recurse)
2931: argstr[x++] = 'r';
2932: if (always_checksum)
2933: argstr[x++] = 'c';
2934: if (cvs_exclude)
2935: argstr[x++] = 'C';
2936: if (ignore_times)
2937: argstr[x++] = 'I';
2938: if (relative_paths)
2939: argstr[x++] = 'R';
2940: if (one_file_system) {
2941: argstr[x++] = 'x';
2942: if (one_file_system > 1)
2943: argstr[x++] = 'x';
2944: }
2945: if (sparse_files)
2946: argstr[x++] = 'S';
2947: if (do_compression == CPRES_ZLIB)
2948: argstr[x++] = 'z';
2949:
2950: set_allow_inc_recurse();
2951:
2952: /* We don't really know the actual protocol_version at this point,
2953: * but checking the pre-negotiated value allows the user to use a
2954: * --protocol=29 override to avoid the use of this -eFLAGS opt. */
2955: if (protocol_version >= 30) {
2956: /* Use "eFlags" alias so that cull_options doesn't think that these are no-arg option letters. */
2957: #define eFlags argstr
2958: /* We make use of the -e option to let the server know about
2959: * any pre-release protocol version && some behavior flags. */
2960: eFlags[x++] = 'e';
2961: #if SUBPROTOCOL_VERSION != 0
2962: if (protocol_version == PROTOCOL_VERSION) {
2963: x += snprintf(argstr+x, sizeof argstr - x,
2964: "%d.%d",
2965: PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
2966: } else
2967: #endif
2968: eFlags[x++] = '.';
2969: if (allow_inc_recurse)
2970: eFlags[x++] = 'i';
2971: #ifdef CAN_SET_SYMLINK_TIMES
2972: eFlags[x++] = 'L'; /* symlink time-setting support */
2973: #endif
2974: #ifdef ICONV_OPTION
2975: eFlags[x++] = 's'; /* symlink iconv translation support */
2976: #endif
2977: eFlags[x++] = 'f'; /* flist I/O-error safety support */
2978: eFlags[x++] = 'x'; /* xattr hardlink optimization not desired */
2979: eFlags[x++] = 'C'; /* support checksum seed order fix */
2980: eFlags[x++] = 'I'; /* support inplace_partial behavior */
2981: eFlags[x++] = 'v'; /* use varint for flist & compat flags; negotiate checksum */
2982: eFlags[x++] = 'u'; /* include name of uid 0 & gid 0 in the id map */
2983: /* NOTE: Avoid using 'V' -- it was the high bit of a write_byte() that became write_varint(). */
2984: #undef eFlags
2985: }
2986:
2987: if (x >= (int)sizeof argstr) { /* Not possible... */
2988: rprintf(FERROR, "argstr overflow in server_options().\n");
2989: exit_cleanup(RERR_MALLOC);
2990: }
2991:
2992: argstr[x] = '\0';
2993:
2994: if (x > 1)
2995: args[ac++] = argstr;
2996:
2997: #ifdef ICONV_OPTION
2998: if (iconv_opt) {
2999: char *set = strchr(iconv_opt, ',');
3000: if (set)
3001: set++;
3002: else
3003: set = iconv_opt;
3004: if (asprintf(&arg, "--iconv=%s", set) < 0)
3005: goto oom;
3006: args[ac++] = arg;
3007: }
3008: #endif
3009:
3010: if (protect_args && !local_server) /* unprotected args stop here */
3011: args[ac++] = NULL;
3012:
3013: if (list_only > 1)
3014: args[ac++] = "--list-only";
3015:
3016: /* This makes sure that the remote rsync can handle deleting with -d
3017: * sans -r because the --no-r option was added at the same time. */
3018: if (xfer_dirs && !recurse && delete_mode && am_sender)
3019: args[ac++] = "--no-r";
3020:
3021: if (preserve_fileflags)
3022: args[ac++] = "--fileflags";
3023:
3024: #ifdef SUPPORT_HFS_COMPRESSION
3025: if (preserve_hfs_compression)
3026: args[ac++] = preserve_hfs_compression == 1 ? "--hfs-compression" : "--protect-decmpfs";
3027: #endif
3028:
3029: if (do_compression && do_compression_level != CLVL_NOT_SPECIFIED) {
3030: if (asprintf(&arg, "--compress-level=%d", do_compression_level) < 0)
3031: goto oom;
3032: args[ac++] = arg;
3033: }
3034:
3035: if (preserve_devices) {
3036: /* Note: sending "--devices" would not be backward-compatible. */
3037: if (!preserve_specials)
3038: args[ac++] = "--no-specials"; /* -D is already set. */
3039: } else if (preserve_specials)
3040: args[ac++] = "--specials";
3041:
3042: /* The server side doesn't use our log-format, but in certain
3043: * circumstances they need to know a little about the option. */
3044: if (stdout_format && am_sender) {
3045: /* Use --log-format, not --out-format, for compatibility. */
3046: if (stdout_format_has_i > 1)
3047: args[ac++] = "--log-format=%i%I";
3048: else if (stdout_format_has_i)
3049: args[ac++] = "--log-format=%i";
3050: else if (stdout_format_has_o_or_i)
3051: args[ac++] = "--log-format=%o";
3052: else if (!verbose)
3053: args[ac++] = "--log-format=X";
3054: }
3055:
3056: if (msgs2stderr == 1)
3057: args[ac++] = "--msgs2stderr";
3058: else if (msgs2stderr == 0)
3059: args[ac++] = "--no-msgs2stderr";
3060:
3061: if (block_size) {
3062: if (asprintf(&arg, "-B%u", (int)block_size) < 0)
3063: goto oom;
3064: args[ac++] = arg;
3065: }
3066:
3067: if (sparse_files_block_size) {
3068: if (asprintf(&arg, "--sparse-block=%lu", sparse_files_block_size) < 0)
3069: goto oom;
3070: args[ac++] = arg;
3071: }
3072:
3073: if (io_timeout) {
3074: if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
3075: goto oom;
3076: args[ac++] = arg;
3077: }
3078:
3079: if (bwlimit) {
3080: if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0)
3081: goto oom;
3082: args[ac++] = arg;
3083: }
3084:
3085: if (backup_dir) {
3086: args[ac++] = "--backup-dir";
3087: args[ac++] = backup_dir;
3088: }
3089: if (backup_dir_dels && backup_dir_dels != backup_dir) {
3090: args[ac++] = "--backup-dir-dels";
3091: args[ac++] = backup_dir_dels;
3092: }
3093:
3094: /* Only send --suffix if it specifies a non-default value. */
3095: if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
3096: /* We use the following syntax to avoid weirdness with '~'. */
3097: if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
3098: goto oom;
3099: args[ac++] = arg;
3100: }
3101: /* Only send --suffix-dels if it specifies a value different from the
3102: * --suffix value, which would normally be used for deletions too. */
3103: if (strcmp(backup_suffix_dels, backup_suffix) != 0) {
3104: /* We use the following syntax to avoid weirdness with '~'. */
3105: if (asprintf(&arg, "--suffix-dels=%s", backup_suffix_dels) < 0)
3106: goto oom;
3107: args[ac++] = arg;
3108: }
3109:
3110: if (checksum_choice) {
3111: if (asprintf(&arg, "--checksum-choice=%s", checksum_choice) < 0)
3112: goto oom;
3113: args[ac++] = arg;
3114: }
3115:
3116: if (do_compression == CPRES_ZLIBX)
3117: args[ac++] = "--new-compress";
3118: else if (compress_choice && do_compression == CPRES_ZLIB)
3119: args[ac++] = "--old-compress";
3120: else if (compress_choice) {
3121: if (asprintf(&arg, "--compress-choice=%s", compress_choice) < 0)
3122: goto oom;
3123: args[ac++] = arg;
3124: }
3125:
3126: if (am_sender) {
3127: /* A remote sender just needs the above -b option.
3128: * A remote receiver will override that with this option. */
3129: if (make_backups == 1)
3130: args[ac++] = "--backup-deleted";
3131: if (max_delete > 0) {
3132: if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
3133: goto oom;
3134: args[ac++] = arg;
3135: } else if (max_delete == 0)
3136: args[ac++] = "--max-delete=-1";
3137: if (min_size >= 0) {
3138: args[ac++] = "--min-size";
3139: args[ac++] = min_size_arg;
3140: }
3141: if (max_size >= 0) {
3142: args[ac++] = "--max-size";
3143: args[ac++] = max_size_arg;
3144: }
3145: if (delete_before)
3146: args[ac++] = "--delete-before";
3147: else if (delete_during == 2)
3148: args[ac++] = "--delete-delay";
3149: else if (delete_during)
3150: args[ac++] = "--delete-during";
3151: else if (delete_after)
3152: args[ac++] = "--delete-after";
3153: else if (delete_mode && !delete_excluded)
3154: args[ac++] = "--delete";
3155: if (delete_excluded)
3156: args[ac++] = "--delete-excluded";
3157: if (force_delete)
3158: args[ac++] = "--force";
3159: #ifdef SUPPORT_FORCE_CHANGE
3160: if (force_change) {
3161: if (force_change == ALL_IMMUTABLE)
3162: args[ac++] = "--force-change";
3163: else if (force_change == USR_IMMUTABLE)
3164: args[ac++] = "--force-uchange";
3165: else if (force_change == SYS_IMMUTABLE)
3166: args[ac++] = "--force-schange";
3167: }
3168: #endif
3169: if (write_batch < 0)
3170: args[ac++] = "--only-write-batch=X";
3171: if (am_root > 1)
3172: args[ac++] = "--super";
3173: if (size_only)
3174: args[ac++] = "--size-only";
3175: if (detect_renamed)
3176: args[ac++] = "--detect-renamed";
3177: if (do_stats)
3178: args[ac++] = "--stats";
3179: } else {
3180: if (skip_compress) {
3181: if (asprintf(&arg, "--skip-compress=%s", skip_compress) < 0)
3182: goto oom;
3183: args[ac++] = arg;
3184: }
3185: if (make_source_backups)
3186: args[ac++] = "--source-backup";
3187: }
3188:
3189: if (max_alloc_arg && max_alloc != DEFAULT_MAX_ALLOC) {
3190: args[ac++] = "--max-alloc";
3191: args[ac++] = max_alloc_arg;
3192: }
3193:
3194: /* --delete-missing-args needs the cooperation of both sides, but
3195: * the sender can handle --ignore-missing-args by itself. */
3196: if (missing_args == 2)
3197: args[ac++] = "--delete-missing-args";
3198: else if (missing_args == 1 && !am_sender)
3199: args[ac++] = "--ignore-missing-args";
3200:
3201: if (date_only)
3202: args[ac++] = "--date-only";
3203:
3204: if (times_only && am_sender)
3205: args[ac++] = "--times-only";
3206:
3207: if (source_filter && !am_sender) {
3208: /* Need to single quote the arg to keep the remote shell
3209: * from splitting it. FIXME: breaks if command has single quotes. */
3210: if (asprintf(&arg, "--source-filter='%s'", source_filter) < 0)
3211: goto oom;
3212: args[ac++] = arg;
3213: }
3214:
3215: if (dest_filter && am_sender) {
3216: /* Need to single quote the arg to keep the remote shell
3217: * from splitting it. FIXME: breaks if command has single quotes. */
3218: if (asprintf(&arg, "--dest-filter='%s'", dest_filter) < 0)
3219: goto oom;
3220: args[ac++] = arg;
3221: }
3222:
3223: if (modify_window_set && am_sender) {
3224: char *fmt = modify_window < 0 ? "-@%d" : "--modify-window=%d";
3225: if (asprintf(&arg, fmt, modify_window) < 0)
3226: goto oom;
3227: args[ac++] = arg;
3228: }
3229:
3230: if (checksum_seed) {
3231: if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
3232: goto oom;
3233: args[ac++] = arg;
3234: }
3235:
3236: if (ignore_case)
3237: args[ac++] = "--ignore-case";
3238:
3239: if (partial_dir && am_sender) {
3240: if (partial_dir != tmp_partialdir) {
3241: args[ac++] = "--partial-dir";
3242: args[ac++] = partial_dir;
3243: }
3244: if (delay_updates)
3245: args[ac++] = "--delay-updates";
3246: } else if (keep_partial && am_sender)
3247: args[ac++] = "--partial";
3248:
3249: if (ignore_errors)
3250: args[ac++] = "--ignore-errors";
3251:
3252: if (copy_unsafe_links)
3253: args[ac++] = "--copy-unsafe-links";
3254:
3255: if (safe_symlinks)
3256: args[ac++] = "--safe-links";
3257:
3258: if (numeric_ids)
3259: args[ac++] = "--numeric-ids";
3260:
3261: if (use_qsort)
3262: args[ac++] = "--use-qsort";
3263:
3264: if (am_sender) {
3265: if (usermap) {
3266: if (asprintf(&arg, "--usermap=%s", usermap) < 0)
3267: goto oom;
3268: args[ac++] = arg;
3269: }
3270:
3271: if (groupmap) {
3272: if (asprintf(&arg, "--groupmap=%s", groupmap) < 0)
3273: goto oom;
3274: args[ac++] = arg;
3275: }
3276:
3277: if (ignore_existing)
3278: args[ac++] = "--ignore-existing";
3279:
3280: /* Backward compatibility: send --existing, not --ignore-non-existing. */
3281: if (ignore_non_existing)
3282: args[ac++] = "--existing";
3283:
3284: if (tmpdir) {
3285: args[ac++] = "--temp-dir";
3286: args[ac++] = tmpdir;
3287: }
3288:
3289: if (do_fsync)
3290: args[ac++] = "--fsync";
3291:
3292: if (basis_dir[0]) {
3293: /* the server only needs this option if it is not the sender,
3294: * and it may be an older version that doesn't know this
3295: * option, so don't send it if client is the sender.
3296: */
3297: for (i = 0; i < basis_dir_cnt; i++) {
3298: args[ac++] = alt_dest_opt(0);
3299: args[ac++] = basis_dir[i];
3300: }
3301: }
3302: }
3303:
3304: /* What flags do we need to send to the other side? */
3305: where = (am_server ? W_CLI : W_SRV) | (am_sender ? W_REC : W_SND);
3306: arg = make_output_option(info_words, info_levels, where);
3307: if (arg)
3308: args[ac++] = arg;
3309:
3310: if (append_mode) {
3311: if (append_mode > 1)
3312: args[ac++] = "--append";
3313: args[ac++] = "--append";
3314: } else if (inplace)
3315: args[ac++] = "--inplace";
3316:
3317: if (link_by_hash_dir && am_sender) {
3318: args[ac++] = "--link-by-hash";
3319: args[ac++] = link_by_hash_dir;
3320: link_by_hash_dir = NULL; /* optimize sending-side checksums */
3321: }
3322:
3323: if (files_from && (!am_sender || filesfrom_host)) {
3324: if (filesfrom_host) {
3325: args[ac++] = "--files-from";
3326: args[ac++] = files_from;
3327: if (eol_nulls)
3328: args[ac++] = "--from0";
3329: } else {
3330: args[ac++] = "--files-from=-";
3331: args[ac++] = "--from0";
3332: }
3333: if (!relative_paths)
3334: args[ac++] = "--no-relative";
3335: }
3336: /* It's OK that this checks the upper-bound of the protocol_version. */
3337: if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30))
3338: args[ac++] = "--no-implied-dirs";
3339:
3340: if (tr_opt) {
3341: if (asprintf(&arg, "--tr=%s", tr_opt) < 0)
3342: goto oom;
3343: args[ac++] = arg;
3344: }
3345:
3346: if (write_devices && am_sender)
3347: args[ac++] = "--write-devices";
3348:
3349: if (remove_source_files == 1)
3350: args[ac++] = "--remove-source-files";
3351: else if (remove_source_files)
3352: args[ac++] = "--remove-sent-files";
3353:
3354: if (copy_devices)
3355: args[ac++] = "--copy-devices";
3356:
3357: if (preallocate_files && am_sender)
3358: args[ac++] = "--preallocate";
3359:
3360: if (open_noatime && preserve_atimes <= 1)
3361: args[ac++] = "--open-noatime";
3362:
3363: if (mkpath_dest_arg && am_sender)
3364: args[ac++] = "--mkpath";
3365:
3366: if (ac > MAX_SERVER_ARGS) { /* Not possible... */
3367: rprintf(FERROR, "argc overflow in server_options().\n");
3368: exit_cleanup(RERR_MALLOC);
3369: }
3370:
3371: if (remote_option_cnt) {
3372: int j;
3373: if (ac + remote_option_cnt > MAX_SERVER_ARGS) {
3374: rprintf(FERROR, "too many remote options specified.\n");
3375: exit_cleanup(RERR_SYNTAX);
3376: }
3377: for (j = 1; j <= remote_option_cnt; j++)
3378: args[ac++] = (char*)remote_options[j];
3379: }
3380:
3381: *argc_p = ac;
3382: return;
3383:
3384: oom:
3385: out_of_memory("server_options");
3386: }
3387:
3388: /* If str points to a valid hostspec, return allocated memory containing the
3389: * [USER@]HOST part of the string, and set the path_start_ptr to the part of
3390: * the string after the host part. Otherwise, return NULL. If port_ptr is
3391: * non-NULL, we must be parsing an rsync:// URL hostname, and we will set
3392: * *port_ptr if a port number is found. Note that IPv6 IPs will have their
3393: * (required for parsing) [ and ] chars elided from the returned string. */
3394: static char *parse_hostspec(char *str, char **path_start_ptr, int *port_ptr)
3395: {
3396: char *s, *host_start = str;
3397: int hostlen = 0, userlen = 0;
3398: char *ret;
3399:
3400: for (s = str; ; s++) {
3401: if (!*s) {
3402: /* It is only OK if we run out of string with rsync:// */
3403: if (!port_ptr)
3404: return NULL;
3405: if (!hostlen)
3406: hostlen = s - host_start;
3407: break;
3408: }
3409: if (*s == ':' || *s == '/') {
3410: if (!hostlen)
3411: hostlen = s - host_start;
3412: if (*s++ == '/') {
3413: if (!port_ptr)
3414: return NULL;
3415: } else if (port_ptr) {
3416: *port_ptr = atoi(s);
3417: while (isDigit(s)) s++;
3418: if (*s && *s++ != '/')
3419: return NULL;
3420: }
3421: break;
3422: }
3423: if (*s == '@') {
3424: userlen = s - str + 1;
3425: host_start = s + 1;
3426: } else if (*s == '[') {
3427: if (s != host_start++)
3428: return NULL;
3429: while (*s && *s != ']' && *s != '/') s++; /*SHARED ITERATOR*/
3430: hostlen = s - host_start;
3431: if (*s != ']' || (s[1] && s[1] != '/' && s[1] != ':') || !hostlen)
3432: return NULL;
3433: }
3434: }
3435:
3436: *path_start_ptr = s;
3437: ret = new_array(char, userlen + hostlen + 1);
3438: if (userlen)
3439: strlcpy(ret, str, userlen + 1);
3440: strlcpy(ret + userlen, host_start, hostlen + 1);
3441: return ret;
3442: }
3443:
3444: /* Look for a HOST specification of the form "HOST:PATH", "HOST::PATH", or
3445: * "rsync://HOST:PORT/PATH". If found, *host_ptr will be set to some allocated
3446: * memory with the HOST. If a daemon-accessing spec was specified, the value
3447: * of *port_ptr will contain a non-0 port number, otherwise it will be set to
3448: * 0. The return value is a pointer to the PATH. Note that the HOST spec can
3449: * be an IPv6 literal address enclosed in '[' and ']' (such as "[::1]" or
3450: * "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */
3451: char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr)
3452: {
3453: char *path;
3454:
3455: if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) {
3456: *host_ptr = parse_hostspec(s + strlen(URL_PREFIX), &path, port_ptr);
3457: if (*host_ptr) {
3458: if (!*port_ptr)
3459: *port_ptr = -1; /* -1 indicates they want the default */
3460: return path;
3461: }
3462: }
3463:
3464: *host_ptr = parse_hostspec(s, &path, NULL);
3465: if (!*host_ptr)
3466: return NULL;
3467:
3468: if (*path == ':') {
3469: if (port_ptr && !*port_ptr)
3470: *port_ptr = -1;
3471: return path + 1;
3472: }
3473: if (port_ptr)
3474: *port_ptr = 0;
3475:
3476: return path;
3477: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>