Annotation of embedaddon/rsync/options.c, revision 1.1.1.4

1.1       misho       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>
1.1.1.4 ! misho       6:  * Copyright (C) 2002-2020 Wayne Davison
1.1       misho       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"
1.1.1.2   misho      23: #include "itypes.h"
1.1.1.4 ! misho      24: #include "ifuncs.h"
1.1       misho      25: #include <popt.h>
                     26: 
1.1.1.4 ! misho      27: extern int direct_io;
1.1       misho      28: extern int module_id;
                     29: extern int local_server;
                     30: extern int sanitize_paths;
                     31: extern unsigned int module_dirlen;
1.1.1.2   misho      32: extern filter_rule_list filter_list;
                     33: extern filter_rule_list daemon_filter_list;
1.1       misho      34: 
                     35: int make_backups = 0;
1.1.1.4 ! misho      36: int make_source_backups = 0;
1.1       misho      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;
1.1.1.4 ! misho      52: int copy_devices = 0;
        !            53: int write_devices = 0;
1.1       misho      54: int preserve_links = 0;
                     55: int preserve_hard_links = 0;
                     56: int preserve_acls = 0;
                     57: int preserve_xattrs = 0;
1.1.1.4 ! misho      58: int preserve_hfs_compression = 0;
1.1       misho      59: int preserve_perms = 0;
1.1.1.4 ! misho      60: int preserve_fileflags = 0;
1.1       misho      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;
1.1.1.4 ! misho      67: int preserve_atimes = 0;
        !            68: int preserve_crtimes = 0;
1.1       misho      69: int update_only = 0;
1.1.1.4 ! misho      70: int downdate_only = 0;
        !            71: int open_noatime = 0;
1.1       misho      72: int cvs_exclude = 0;
                     73: int dry_run = 0;
                     74: int do_xfers = 1;
1.1.1.4 ! misho      75: int do_fsync = 0;
1.1       misho      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;
1.1.1.4 ! misho      82: int diffserv = 8;
        !            83: char *congestion_alg = NULL;
1.1       misho      84: int remove_source_files = 0;
1.1.1.4 ! misho      85: int omit_dir_changes = 0;
1.1       misho      86: int one_file_system = 0;
                     87: int protocol_version = PROTOCOL_VERSION;
                     88: int sparse_files = 0;
1.1.1.4 ! misho      89: long sparse_files_block_size = SPARSE_WRITE_SIZE;
1.1.1.2   misho      90: int preallocate_files = 0;
1.1       misho      91: int do_compression = 0;
1.1.1.4 ! misho      92: int do_compression_level = CLVL_NOT_SPECIFIED;
1.1       misho      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;
1.1.1.4 ! misho      97: int am_dbadmin = 0;
1.1       misho      98: int relative_paths = -1;
1.1.1.4 ! misho      99: int detect_renamed = 0;
1.1       misho     100: int implied_dirs = 1;
1.1.1.2   misho     101: int missing_args = 0; /* 0 = FERROR_XFER, 1 = ignore, 2 = delete */
1.1       misho     102: int numeric_ids = 0;
1.1.1.4 ! misho     103: int msgs2stderr = 2; /* Default: send errors to stderr for local & remote-shell transfers */
1.1       misho     104: int allow_8bit_chars = 0;
                    105: int force_delete = 0;
1.1.1.4 ! misho     106: int force_change = 0;
1.1       misho     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;
1.1.1.4 ! misho     113: char *db_config = NULL;
1.1       misho     114: int eol_nulls = 0;
1.1.1.2   misho     115: int protect_args = -1;
                    116: int human_readable = 1;
1.1       misho     117: int recurse = 0;
1.1.1.4 ! misho     118: int mkpath_dest_arg = 0;
1.1       misho     119: int allow_inc_recurse = 1;
                    120: int xfer_dirs = -1;
                    121: int am_daemon = 0;
1.1.1.4 ! misho     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;
1.1       misho     125: int connect_timeout = 0;
                    126: int keep_partial = 0;
                    127: int safe_symlinks = 0;
                    128: int copy_unsafe_links = 0;
1.1.1.2   misho     129: int munge_symlinks = 0;
1.1       misho     130: int size_only = 0;
1.1.1.4 ! misho     131: int date_only = 0;
1.1       misho     132: int daemon_bwlimit = 0;
                    133: int bwlimit = 0;
                    134: int fuzzy_basis = 0;
1.1.1.4 ! misho     135: unsigned long sleep_asec = 0;
1.1       misho     136: size_t bwlimit_writemax = 0;
                    137: int ignore_existing = 0;
                    138: int ignore_non_existing = 0;
                    139: int need_messages_from_generator = 0;
1.1.1.4 ! misho     140: int checksum_files = CSF_IGNORE_FILES;
1.1       misho     141: int max_delete = INT_MIN;
1.1.1.2   misho     142: OFF_T max_size = -1;
                    143: OFF_T min_size = -1;
1.1       misho     144: int ignore_errors = 0;
                    145: int modify_window = 0;
1.1.1.4 ! misho     146: int ignore_case = 0;
1.1       misho     147: int blocking_io = -1;
                    148: int checksum_seed = 0;
                    149: int inplace = 0;
                    150: int delay_updates = 0;
1.1.1.4 ! misho     151: int32 block_size = 0;
        !           152: time_t stop_at_utime = 0;
1.1       misho     153: char *skip_compress = NULL;
1.1.1.4 ! misho     154: char *copy_as = NULL;
1.1.1.2   misho     155: item_list dparam_list = EMPTY_ITEM_LIST;
1.1       misho     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;
1.1.1.4 ! misho     182: int backup_dir_dels_len = 0;
1.1       misho     183: int backup_suffix_len;
1.1.1.4 ! misho     184: int backup_suffix_dels_len;
1.1       misho     185: unsigned int backup_dir_remainder;
1.1.1.4 ! misho     186: unsigned int backup_dir_dels_remainder;
1.1       misho     187: 
                    188: char *backup_suffix = NULL;
1.1.1.4 ! misho     189: char *backup_suffix_dels = NULL;
1.1       misho     190: char *tmpdir = NULL;
                    191: char *partial_dir = NULL;
                    192: char *basis_dir[MAX_BASIS_DIRS+1];
1.1.1.4 ! misho     193: char *link_by_hash_dir = NULL;
1.1       misho     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;
1.1.1.4 ! misho     200: char *source_filter = NULL;
        !           201: char *dest_filter = NULL;
        !           202: char *early_input_file = NULL;
1.1       misho     203: char *rsync_path = RSYNC_PATH;
                    204: char *backup_dir = NULL;
1.1.1.4 ! misho     205: char *backup_dir_dels = NULL;
1.1       misho     206: char backup_dir_buf[MAXPATHLEN];
1.1.1.4 ! misho     207: char backup_dir_dels_buf[MAXPATHLEN];
1.1       misho     208: char *sockopts = NULL;
1.1.1.2   misho     209: char *usermap = NULL;
                    210: char *groupmap = NULL;
1.1       misho     211: int rsync_port = 0;
1.1.1.4 ! misho     212: int alt_dest_type = 0;
1.1       misho     213: int basis_dir_cnt = 0;
                    214: 
1.1.1.4 ! misho     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;
1.1.1.2   misho     220: static int remote_option_alloc = 0;
                    221: int remote_option_cnt = 0;
                    222: const char **remote_options = NULL;
1.1.1.4 ! misho     223: const char *checksum_choice = NULL;
        !           224: const char *compress_choice = NULL;
1.1.1.2   misho     225: 
1.1       misho     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;
1.1.1.4 ! misho     235: char *tr_opt = NULL;
1.1       misho     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;
1.1.1.4 ! misho     241: char *iconv_opt =
1.1       misho     242: #ifdef ICONV_OPTION
1.1.1.4 ! misho     243:                ICONV_OPTION;
        !           244: #else
        !           245:                NULL;
1.1       misho     246: #endif
                    247: 
                    248: struct chmod_mode_struct *chmod_modes = NULL;
                    249: 
1.1.1.2   misho     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",
1.1.1.4 ! misho     256:        /*5*/ "CHDIR,DELTASUM4,FLIST4,FUZZY2,HASH,HASHLINK,HLINK",
1.1.1.2   misho     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)"),
1.1.1.4 ! misho     317:        DEBUG_WORD(DB, W_SND|W_REC, "Debug DB operations (levels 1-5)"),
1.1.1.2   misho     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"),
1.1.1.4 ! misho     327:        DEBUG_WORD(HASHLINK, W_REC, "Debug hashlink code (levels 1-2)"),
1.1.1.2   misho     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)"),
1.1.1.4 ! misho     331:        DEBUG_WORD(NSTR, W_CLI|W_SRV, "Debug negotiation strings"),
1.1.1.2   misho     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;
1.1       misho     343: static int daemon_opt;   /* sets am_daemon after option error-reporting */
                    344: static int omit_dir_times = 0;
1.1.1.2   misho     345: static int omit_link_times = 0;
1.1       misho     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;
1.1.1.2   misho     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;
1.1       misho     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: 
1.1.1.2   misho     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++;
1.1.1.4 ! misho     419:        buf = new_array(char, len);
1.1.1.2   misho     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: 
1.1.1.4 ! misho     452: static void parse_output_words(struct output_struct *words, short *levels, const char *str, uchar priority)
1.1.1.2   misho     453: {
                    454:        const char *s;
                    455:        int j, len, lev;
                    456: 
1.1.1.3   misho     457:        for ( ; str; str = s) {
1.1.1.2   misho     458:                if ((s = strchr(str, ',')) != NULL)
                    459:                        len = s++ - str;
                    460:                else
                    461:                        len = strlen(str);
1.1.1.3   misho     462:                if (!len)
                    463:                        continue;
                    464:                if (!isDigit(str)) {
                    465:                        while (len && isDigit(str+len-1))
                    466:                                len--;
                    467:                }
1.1.1.2   misho     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:                }
1.1.1.4 ! misho     490:                if (len && !words[j].name && !am_server) {
1.1.1.2   misho     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: }
1.1       misho     604: 
1.1.1.4 ! misho     605: enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
1.1       misho     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,
1.1.1.4 ! misho     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};
1.1       misho     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 },
1.1.1.4 ! misho     618:   {"version",         'V', POPT_ARG_NONE,   0, 'V', 0, 0},
1.1       misho     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 },
1.1.1.2   misho     622:   {"info",             0,  POPT_ARG_STRING, 0, OPT_INFO, 0, 0 },
                    623:   {"debug",            0,  POPT_ARG_STRING, 0, OPT_DEBUG, 0, 0 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     651:   {"fileflags",        0,  POPT_ARG_VAL,    &preserve_fileflags, 1, 0, 0 },
        !           652:   {"no-fileflags",     0,  POPT_ARG_VAL,    &preserve_fileflags, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.2   misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     692:   {"copy-devices",     0,  POPT_ARG_NONE,   &copy_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 },
1.1       misho     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,   &copy_links, 0, 0, 0 },
                    701:   {"copy-unsafe-links",0,  POPT_ARG_NONE,   &copy_unsafe_links, 0, 0, 0 },
                    702:   {"safe-links",       0,  POPT_ARG_NONE,   &safe_symlinks, 0, 0, 0 },
1.1.1.2   misho     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 },
1.1       misho     705:   {"copy-dirlinks",   'k', POPT_ARG_NONE,   &copy_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 },
1.1.1.4 ! misho     720:   {"date-only",        0,  POPT_ARG_NONE,   &date_only, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     725:   {"downdate",        'w', POPT_ARG_NONE,   &downdate_only, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     731:   {"max-alloc",        0,  POPT_ARG_STRING, &max_alloc_arg, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     735:   {"sparse-block",     0,  POPT_ARG_LONG,   &sparse_files_block_size, 0, 0, 0 },
1.1.1.2   misho     736:   {"preallocate",      0,  POPT_ARG_NONE,   &preallocate_files, 0, 0, 0},
1.1       misho     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 },
1.1.1.2   misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     788:   {"clone-dest",       0,  POPT_ARG_STRING, 0, OPT_CLONE_DEST, 0, 0 },
1.1.1.2   misho     789:   {"fuzzy",           'y', POPT_ARG_NONE,   0, 'y', 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     799:   {"skip-compress",    0,  POPT_ARG_STRING, &skip_compress, 0, 0, 0 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     822:   {"slow-down",        0,  POPT_ARG_LONG,   &sleep_asec, 0, 0, 0 },
1.1.1.2   misho     823:   {"bwlimit",          0,  POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 },
1.1       misho     824:   {"no-bwlimit",       0,  POPT_ARG_VAL,    &bwlimit, 0, 0, 0 },
1.1.1.4 ! misho     825:   {"backup",          'b', POPT_ARG_VAL,    &make_backups, 2, 0, 0 },
        !           826:   {"backup-deleted",   0,  POPT_ARG_VAL,    &make_backups, 1, 0, 0 },
1.1       misho     827:   {"no-backup",        0,  POPT_ARG_VAL,    &make_backups, 0, 0, 0 },
                    828:   {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
1.1.1.4 ! misho     829:   {"backup-dir-dels",  0,  POPT_ARG_STRING, &backup_dir_dels, 0, 0, 0 },
1.1       misho     830:   {"suffix",           0,  POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
1.1.1.4 ! misho     831:   {"suffix-dels",      0,  POPT_ARG_STRING, &backup_suffix_dels, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.2   misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.4 ! misho     862:   {"tr",               0,  POPT_ARG_STRING, &tr_opt, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     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 },
1.1       misho     870:   {"qsort",            0,  POPT_ARG_NONE,   &use_qsort, 0, 0, 0 },
1.1.1.4 ! misho     871:   {"copy-as",          0,  POPT_ARG_STRING, &copy_as, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     876:   {"early-input",      0,  POPT_ARG_STRING, &early_input_file, 0, 0, 0 },
1.1       misho     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 },
1.1.1.4 ! misho     879:   {"source-filter",    0,  POPT_ARG_STRING, &source_filter, 0, 0, 0 },
        !           880:   {"dest-filter",      0,  POPT_ARG_STRING, &dest_filter, 0, 0, 0 },
1.1.1.2   misho     881:   {"outbuf",           0,  POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 },
                    882:   {"remote-option",   'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
1.1       misho     883:   {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
1.1.1.4 ! misho     884:   {"congestion-alg",   0,  POPT_ARG_STRING, &congestion_alg, 0, 0, 0 },
        !           885:   {"diffserv",         0,  POPT_ARG_INT,    &diffserv, 0, 0, 0 },
1.1       misho     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 },
1.1.1.2   misho     892:   {"dparam",           0,  POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
1.1       misho     893:   {"detach",           0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
                    894:   {"no-detach",        0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
1.1.1.4 ! misho     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 },
1.1       misho     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 },
1.1.1.2   misho     907:   {"dparam",          'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
1.1       misho     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: 
1.1.1.4 ! misho     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: };
1.1       misho     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);
1.1.1.4 ! misho     969:        io_flush(MSG_FLUSH);
1.1       misho     970:        msleep(20);
                    971: }
                    972: 
                    973: 
1.1.1.4 ! misho     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: 
1.1       misho    1007: /**
                   1008:  * Tweak the option table to disable all options that the rsyncd.conf
                   1009:  * file has told us to refuse.
                   1010:  **/
1.1.1.4 ! misho    1011: static void set_refuse_options(void)
1.1       misho    1012: {
1.1.1.4 ! misho    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);
1.1       misho    1050: 
1.1.1.4 ! misho    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:        }
1.1       misho    1055: 
                   1056:        while (1) {
1.1.1.4 ! misho    1057:                while (*ref == ' ') ref++;
        !          1058:                if (!*ref)
1.1       misho    1059:                        break;
1.1.1.4 ! misho    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);
1.1       misho    1066:                if (!cp)
                   1067:                        break;
                   1068:                *cp = ' ';
1.1.1.4 ! misho    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:                }
1.1       misho    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: 
1.1.1.4 ! misho    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)
1.1       misho    1175: {
1.1.1.4 ! misho    1176:        int reps, mult, len;
        !          1177:        const char *arg, *err = "invalid", *min_max = NULL;
        !          1178:        ssize_t limit = -1, size = 1;
1.1       misho    1179: 
1.1.1.4 ! misho    1180:        for (arg = size_arg; isDigit(arg); arg++) {}
        !          1181:        if (*arg == '.' || *arg == get_decimal_point()) /* backward compatibility: always allow '.' */
1.1       misho    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;
1.1.1.4 ! misho    1196:        case 't': case 'T':
        !          1197:                reps = 4;
        !          1198:                break;
        !          1199:        case 'p': case 'P':
        !          1200:                reps = 5;
        !          1201:                break;
1.1       misho    1202:        default:
1.1.1.4 ! misho    1203:                goto failure;
1.1       misho    1204:        }
                   1205:        if (*arg == 'b' || *arg == 'B')
1.1.1.4 ! misho    1206:                mult = 1000, arg++;
1.1       misho    1207:        else if (!*arg || *arg == '+' || *arg == '-')
                   1208:                mult = 1024;
                   1209:        else if (strncasecmp(arg, "ib", 2) == 0)
                   1210:                mult = 1024, arg += 2;
                   1211:        else
1.1.1.4 ! misho    1212:                goto failure;
1.1       misho    1213:        while (reps--)
                   1214:                size *= mult;
1.1.1.4 ! misho    1215:        size *= atof(size_arg);
        !          1216:        if ((*arg == '+' || *arg == '-') && arg[1] == '1' && arg != size_arg)
        !          1217:                size += atoi(arg), arg += 2;
1.1       misho    1218:        if (*arg)
1.1.1.4 ! misho    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;
1.1       misho    1231:        }
                   1232:        return size;
1.1.1.4 ! misho    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;
1.1       misho    1244: }
                   1245: 
1.1.1.4 ! misho    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
1.1       misho    1387: 
                   1388: static void create_refuse_error(int which)
                   1389: {
1.1.1.4 ! misho    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: 
1.1       misho    1398:        /* The "which" value is the index + OPT_REFUSED_BASE. */
                   1399:        struct poptOption *op = &long_options[which - OPT_REFUSED_BASE];
1.1.1.4 ! misho    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:                }
1.1       misho    1476:        }
1.1.1.4 ! misho    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);
1.1       misho    1517: }
                   1518: 
1.1.1.4 ! misho    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: }
1.1       misho    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;
1.1.1.4 ! misho    1551:        int opt, want_dest_type;
        !          1552:        int orig_protect_args = protect_args;
1.1       misho    1553: 
1.1.1.4 ! misho    1554:        if (argc == 0) {
        !          1555:                strlcpy(err_buf, "argc is zero!\n", sizeof err_buf);
        !          1556:                return 0;
1.1       misho    1557:        }
                   1558: 
1.1.1.4 ! misho    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: 
1.1       misho    1567: #ifdef ICONV_OPTION
1.1.1.2   misho    1568:        if (!am_daemon && protect_args <= 0 && (arg = getenv("RSYNC_ICONV")) != NULL && *arg)
1.1       misho    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);
1.1.1.4 ! misho    1579:        if (!am_server) {
1.1       misho    1580:                poptReadDefaultConfig(pc, 0);
1.1.1.4 ! misho    1581:                popt_unalias(pc, "--daemon");
        !          1582:                popt_unalias(pc, "--server");
        !          1583:        }
1.1       misho    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) {
1.1.1.4 ! misho    1590:                case 'V':
        !          1591:                        version_opt_cnt++;
        !          1592:                        break;
1.1       misho    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);
1.1.1.4 ! misho    1599:                                pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0);
1.1       misho    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
1.1.1.2   misho    1625:                        protect_args = 0;
1.1       misho    1626:                        poptFreeContext(pc);
1.1.1.4 ! misho    1627:                        pc = poptGetContext(RSYNC_NAME, argc, argv, long_daemon_options, 0);
1.1       misho    1628:                        while ((opt = poptGetNextOpt(pc)) != -1) {
1.1.1.2   misho    1629:                                char **cpp;
1.1       misho    1630:                                switch (opt) {
                   1631:                                case 'h':
                   1632:                                        daemon_usage(FINFO);
                   1633:                                        exit_cleanup(0);
                   1634: 
1.1.1.2   misho    1635:                                case 'M':
                   1636:                                        arg = poptGetOptArg(pc);
                   1637:                                        if (!strchr(arg, '=')) {
                   1638:                                                rprintf(FERROR,
1.1.1.4 ! misho    1639:                                                        "--dparam value is missing an '=': %s\n",
        !          1640:                                                        arg);
1.1.1.2   misho    1641:                                                goto daemon_error;
                   1642:                                        }
                   1643:                                        cpp = EXPAND_ITEM_LIST(&dparam_list, char *, 4);
                   1644:                                        *cpp = strdup(arg);
                   1645:                                        break;
                   1646: 
1.1       misho    1647:                                case 'v':
                   1648:                                        verbose++;
                   1649:                                        break;
                   1650: 
                   1651:                                default:
                   1652:                                        rprintf(FERROR,
1.1.1.4 ! misho    1653:                                                "rsync: %s: %s (in daemon mode)\n",
        !          1654:                                                poptBadOption(pc, POPT_BADOPTION_NOALIAS),
        !          1655:                                                poptStrerror(opt));
1.1       misho    1656:                                        goto daemon_error;
                   1657:                                }
                   1658:                        }
                   1659: 
1.1.1.2   misho    1660:                        if (dparam_list.count && !set_dparams(1))
                   1661:                                exit_cleanup(RERR_SYNTAX);
                   1662: 
1.1       misho    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:
1.1.1.4 ! misho    1672:                                rprintf(FERROR, "(Type \"rsync --daemon --help\" for assistance with daemon mode.)\n");
1.1       misho    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: 
1.1.1.4 ! misho    1683:                case OPT_DBONLY:
        !          1684:                        protect_args = 0;
        !          1685:                        poptFreeContext(pc);
        !          1686:                        parse_dbonly_args(argc, argv);
        !          1687:                        break; /* NOT REACHED */
        !          1688: 
1.1       misho    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:
1.1.1.2   misho    1697:                        parse_filter_str(&filter_list, poptGetOptArg(pc),
                   1698:                                        rule_template(0), 0);
1.1       misho    1699:                        break;
                   1700: 
                   1701:                case OPT_EXCLUDE:
1.1.1.2   misho    1702:                        parse_filter_str(&filter_list, poptGetOptArg(pc),
                   1703:                                        rule_template(0), XFLG_OLD_PREFIXES);
1.1       misho    1704:                        break;
                   1705: 
                   1706:                case OPT_INCLUDE:
1.1.1.2   misho    1707:                        parse_filter_str(&filter_list, poptGetOptArg(pc),
                   1708:                                        rule_template(FILTRULE_INCLUDE), XFLG_OLD_PREFIXES);
1.1       misho    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;
1.1.1.2   misho    1718:                                char *cp = strdup(arg);
1.1       misho    1719:                                if (!*cp)
1.1.1.2   misho    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:                                }
1.1       misho    1726:                                free(cp);
                   1727:                                if (rej)
                   1728:                                        goto options_rejected;
                   1729:                        }
                   1730:                        parse_filter_file(&filter_list, arg,
1.1.1.2   misho    1731:                                rule_template(opt == OPT_INCLUDE_FROM ? FILTRULE_INCLUDE : 0),
1.1       misho    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: 
1.1.1.4 ! misho    1761:                case OPT_NO_DB:
        !          1762:                        db_config = NULL;
        !          1763:                        break;
        !          1764: 
1.1       misho    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: 
1.1.1.4 ! misho    1777:                case 'U':
        !          1778:                        if (++preserve_atimes > 1)
        !          1779:                                open_noatime = 1;
        !          1780:                        break;
        !          1781: 
1.1       misho    1782:                case 'v':
                   1783:                        verbose++;
                   1784:                        break;
                   1785: 
1.1.1.2   misho    1786:                case 'y':
                   1787:                        fuzzy_basis++;
                   1788:                        break;
                   1789: 
1.1       misho    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:
1.1.1.2   misho    1801:                                parse_filter_str(&filter_list,": /.rsync-filter",rule_template(0),0);
1.1       misho    1802:                                break;
                   1803:                        case 2:
1.1.1.2   misho    1804:                                parse_filter_str(&filter_list,"- .rsync-filter",rule_template(0),0);
1.1       misho    1805:                                break;
                   1806:                        }
                   1807:                        break;
                   1808: 
                   1809:                case 'P':
                   1810:                        if (refused_partial || refused_progress) {
1.1.1.4 ! misho    1811:                                create_refuse_error(refused_partial ? refused_partial : refused_progress);
1.1       misho    1812:                                return 0;
                   1813:                        }
                   1814:                        do_progress = 1;
                   1815:                        keep_partial = 1;
                   1816:                        break;
                   1817: 
                   1818:                case 'z':
1.1.1.3   misho    1819:                        do_compression++;
1.1       misho    1820:                        break;
                   1821: 
1.1.1.4 ! misho    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: 
1.1.1.2   misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    1887:                case OPT_MAX_SIZE:
1.1.1.4 ! misho    1888:                        if ((max_size = parse_size_arg(max_size_arg, 'b', "max-size", 0, -1, False)) < 0)
1.1       misho    1889:                                return 0;
1.1.1.4 ! misho    1890:                        max_size_arg = strdup(do_big_num(max_size, 0, NULL));
1.1       misho    1891:                        break;
                   1892: 
                   1893:                case OPT_MIN_SIZE:
1.1.1.4 ! misho    1894:                        if ((min_size = parse_size_arg(min_size_arg, 'b', "min-size", 0, -1, False)) < 0)
1.1       misho    1895:                                return 0;
1.1.1.4 ! misho    1896:                        min_size_arg = strdup(do_big_num(min_size, 0, NULL));
1.1       misho    1897:                        break;
                   1898: 
1.1.1.4 ! misho    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;
1.1.1.2   misho    1905:                        break;
1.1.1.4 ! misho    1906:                }
1.1.1.2   misho    1907: 
1.1       misho    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:
1.1.1.4 ! misho    1916:                        want_dest_type = LINK_DEST;
        !          1917:                        goto set_dest_dir;
        !          1918: 
        !          1919:                case OPT_CLONE_DEST:
        !          1920:                        want_dest_type = CLONE_DEST;
1.1       misho    1921:                        goto set_dest_dir;
                   1922: 
                   1923:                case OPT_COPY_DEST:
1.1.1.4 ! misho    1924:                        want_dest_type = COPY_DEST;
1.1       misho    1925:                        goto set_dest_dir;
                   1926: 
                   1927:                case OPT_COMPARE_DEST:
1.1.1.4 ! misho    1928:                        want_dest_type = COMPARE_DEST;
        !          1929: 
1.1       misho    1930:                set_dest_dir:
1.1.1.4 ! misho    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: 
1.1       misho    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",
1.1.1.4 ! misho    1942:                                        MAX_BASIS_DIRS, alt_dest_opt(0));
1.1       misho    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,
1.1.1.4 ! misho    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",
1.1       misho    1980:                                    arg);
                   1981:                                return 0;
                   1982:                        }
                   1983:                        break;
                   1984: 
1.1.1.2   misho    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,
1.1.1.4 ! misho    1999:                                                "--usermap conflicts with prior --chown.\n");
1.1.1.2   misho    2000:                                        return 0;
                   2001:                                }
                   2002:                                snprintf(err_buf, sizeof err_buf,
1.1.1.4 ! misho    2003:                                        "You can only specify --usermap once.\n");
1.1.1.2   misho    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,
1.1.1.4 ! misho    2014:                                                "--groupmap conflicts with prior --chown.\n");
1.1.1.2   misho    2015:                                        return 0;
                   2016:                                }
                   2017:                                snprintf(err_buf, sizeof err_buf,
1.1.1.4 ! misho    2018:                                        "You can only specify --groupmap once.\n");
1.1.1.2   misho    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,
1.1.1.4 ! misho    2036:                                                        "--chown conflicts with prior --usermap.\n");
1.1.1.2   misho    2037:                                                return 0;
                   2038:                                        }
                   2039:                                        snprintf(err_buf, sizeof err_buf,
1.1.1.4 ! misho    2040:                                                "You can only specify a user-affecting --chown once.\n");
1.1.1.2   misho    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,
1.1.1.4 ! misho    2051:                                                        "--chown conflicts with prior --groupmap.\n");
1.1.1.2   misho    2052:                                                return 0;
                   2053:                                        }
                   2054:                                        snprintf(err_buf, sizeof err_buf,
1.1.1.4 ! misho    2055:                                                "You can only specify a group-affecting --chown once.\n");
1.1.1.2   misho    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: 
1.1       misho    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),
1.1.1.4 ! misho    2081:                                 "ACLs are not supported on this %s\n",
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1.1.2   misho    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: 
1.1.1.4 ! misho    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: 
1.1.1.2   misho    2209:        if (human_readable > 1 && argc == 2 && !am_server) {
1.1       misho    2210:                /* Allow the old meaning of 'h' (--help) on its own. */
                   2211:                usage(FINFO);
                   2212:                exit_cleanup(0);
                   2213:        }
                   2214: 
1.1.1.4 ! misho    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;
1.1.1.3   misho    2225:                if (do_compression && refused_compress) {
                   2226:                        create_refuse_error(refused_compress);
                   2227:                        return 0;
                   2228:                }
                   2229:        }
                   2230: 
1.1.1.2   misho    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: 
1.1.1.4 ! misho    2257:        if (msgs2stderr == 1) { /* Are all messages going to stderr? */
1.1.1.2   misho    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: 
1.1       misho    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: 
1.1.1.2   misho    2284:        if (fuzzy_basis > 1)
                   2285:                fuzzy_basis = basis_dir_cnt + 1;
                   2286: 
1.1.1.4 ! misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    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;
1.1.1.2   misho    2338:        }
1.1.1.4 ! misho    2339: #endif
1.1.1.2   misho    2340: 
1.1       misho    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) {
1.1.1.2   misho    2400:                parse_filter_str(&filter_list, "- /*/*", rule_template(0), 0);
1.1       misho    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: 
1.1.1.2   misho    2438:        if (missing_args == 3) /* simplify if both options were specified */
                   2439:                missing_args = 2;
                   2440:        if (refused_delete && (delete_mode || missing_args == 2)) {
1.1       misho    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: 
1.1.1.2   misho    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: 
1.1       misho    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);
1.1.1.4 ! misho    2475:                if (backup_dir_dels)
        !          2476:                        backup_dir_dels = sanitize_path(NULL, backup_dir_dels, NULL, 0, SP_DEFAULT);
1.1       misho    2477:        }
                   2478:        if (daemon_filter_list.head && !am_sender) {
1.1.1.2   misho    2479:                filter_rule_list *elp = &daemon_filter_list;
1.1       misho    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:                }
1.1.1.4 ! misho    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:                }
1.1       misho    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:        }
1.1.1.4 ! misho    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:        }
1.1       misho    2531:        if (backup_dir) {
1.1.1.2   misho    2532:                size_t len;
1.1.1.4 ! misho    2533:                make_backups = 1; /* --backup-dir implies --backup */
1.1.1.2   misho    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);
1.1       misho    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;
1.1.1.2   misho    2545:                if (!backup_dir_len) {
                   2546:                        backup_dir_len = -1;
                   2547:                        backup_dir = NULL;
                   2548:                } else if (backup_dir_buf[backup_dir_len - 1] != '/') {
1.1       misho    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;
1.1.1.2   misho    2553:        }
                   2554:        if (backup_dir) {
                   2555:                /* No need for a suffix or a protect rule. */
1.1       misho    2556:        } else if (!backup_suffix_len && (!am_server || !am_sender)) {
                   2557:                snprintf(err_buf, sizeof err_buf,
1.1.1.2   misho    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");
1.1       misho    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);
1.1.1.2   misho    2565:                parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0);
1.1       misho    2566:        }
1.1.1.4 ! misho    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;
1.1       misho    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
1.1.1.2   misho    2604:                if (!omit_link_times)
                   2605:                        preserve_times |= PRESERVE_LINK_TIMES;
1.1       misho    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')
1.1.1.2   misho    2620:                 && !log_format_has(stdout_format, 'c')
                   2621:                 && !log_format_has(stdout_format, 'C'))
1.1       misho    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: 
1.1.1.2   misho    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:        }
1.1       misho    2634: 
                   2635:        if (dry_run)
                   2636:                do_xfers = 0;
                   2637: 
                   2638:        set_io_timeout(io_timeout);
                   2639: 
1.1.1.2   misho    2640:        if (INFO_GTE(NAME, 1) && !stdout_format) {
1.1       misho    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: 
1.1.1.4 ! misho    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)
1.1       misho    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",
1.1.1.4 ! misho    2699:                                 detect_renamed ? "detect-renamed" :
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    2745:        if (files_from) {
                   2746:                char *h, *p;
                   2747:                int q;
1.1.1.2   misho    2748:                if (argc > 2 || (!am_daemon && !am_server && argc == 1)) {
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    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;
1.1.1.2   misho    2832:        uchar where;
1.1       misho    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: 
1.1.1.4 ! misho    2851:        if (quiet && msgs2stderr)
        !          2852:                argstr[x++] = 'q';
1.1       misho    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';
1.1.1.2   misho    2871:                if (omit_link_times)
                   2872:                        argstr[x++] = 'J';
1.1.1.4 ! misho    2873:                if (omit_dir_changes == 1)
        !          2874:                        args[ac++] = "--omit-dir-changes";
1.1.1.2   misho    2875:                if (fuzzy_basis) {
                   2876:                        argstr[x++] = 'y';
                   2877:                        if (fuzzy_basis > 1)
                   2878:                                argstr[x++] = 'y';
                   2879:                }
1.1       misho    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';
1.1.1.4 ! misho    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
1.1       misho    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';
1.1.1.4 ! misho    2947:        if (do_compression == CPRES_ZLIB)
1.1       misho    2948:                argstr[x++] = 'z';
                   2949: 
                   2950:        set_allow_inc_recurse();
                   2951: 
1.1.1.3   misho    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. */
1.1       misho    2955:        if (protocol_version >= 30) {
1.1.1.3   misho    2956:                /* Use "eFlags" alias so that cull_options doesn't think that these are no-arg option letters. */
                   2957: #define eFlags argstr
1.1       misho    2958:                /* We make use of the -e option to let the server know about
                   2959:                 * any pre-release protocol version && some behavior flags. */
1.1.1.3   misho    2960:                eFlags[x++] = 'e';
1.1       misho    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
1.1.1.3   misho    2968:                        eFlags[x++] = '.';
1.1       misho    2969:                if (allow_inc_recurse)
1.1.1.3   misho    2970:                        eFlags[x++] = 'i';
1.1       misho    2971: #ifdef CAN_SET_SYMLINK_TIMES
1.1.1.3   misho    2972:                eFlags[x++] = 'L'; /* symlink time-setting support */
1.1       misho    2973: #endif
                   2974: #ifdef ICONV_OPTION
1.1.1.3   misho    2975:                eFlags[x++] = 's'; /* symlink iconv translation support */
1.1       misho    2976: #endif
1.1.1.3   misho    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 */
1.1.1.4 ! misho    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(). */
1.1.1.3   misho    2984: #undef eFlags
1.1       misho    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: 
1.1.1.4 ! misho    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)
1.1       misho    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: 
1.1.1.4 ! misho    3056:        if (msgs2stderr == 1)
        !          3057:                args[ac++] = "--msgs2stderr";
        !          3058:        else if (msgs2stderr == 0)
        !          3059:                args[ac++] = "--no-msgs2stderr";
        !          3060: 
1.1       misho    3061:        if (block_size) {
1.1.1.4 ! misho    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)
1.1       misho    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:        }
1.1.1.4 ! misho    3089:        if (backup_dir_dels && backup_dir_dels != backup_dir) {
        !          3090:                args[ac++] = "--backup-dir-dels";
        !          3091:                args[ac++] = backup_dir_dels;
        !          3092:        }
1.1       misho    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:        }
1.1.1.4 ! misho    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:        }
1.1       misho    3125: 
                   3126:        if (am_sender) {
1.1.1.4 ! misho    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";
1.1       misho    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";
1.1.1.2   misho    3137:                if (min_size >= 0) {
1.1       misho    3138:                        args[ac++] = "--min-size";
                   3139:                        args[ac++] = min_size_arg;
                   3140:                }
1.1.1.2   misho    3141:                if (max_size >= 0) {
1.1       misho    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";
1.1.1.4 ! misho    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
1.1       misho    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";
1.1.1.4 ! misho    3175:                if (detect_renamed)
        !          3176:                        args[ac++] = "--detect-renamed";
1.1.1.2   misho    3177:                if (do_stats)
                   3178:                        args[ac++] = "--stats";
1.1       misho    3179:        } else {
                   3180:                if (skip_compress) {
                   3181:                        if (asprintf(&arg, "--skip-compress=%s", skip_compress) < 0)
                   3182:                                goto oom;
                   3183:                        args[ac++] = arg;
                   3184:                }
1.1.1.4 ! misho    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;
1.1       misho    3192:        }
                   3193: 
1.1.1.2   misho    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: 
1.1.1.4 ! misho    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)
1.1       misho    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: 
1.1.1.4 ! misho    3236:        if (ignore_case)
        !          3237:                args[ac++] = "--ignore-case";
        !          3238: 
1.1       misho    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) {
1.1.1.2   misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    3289:                if (do_fsync)
        !          3290:                        args[ac++] = "--fsync";
        !          3291: 
1.1       misho    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++) {
1.1.1.4 ! misho    3298:                                args[ac++] = alt_dest_opt(0);
1.1       misho    3299:                                args[ac++] = basis_dir[i];
                   3300:                        }
                   3301:                }
                   3302:        }
                   3303: 
1.1.1.2   misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    3354:        if (copy_devices)
        !          3355:                args[ac++] = "--copy-devices";
        !          3356: 
1.1.1.2   misho    3357:        if (preallocate_files && am_sender)
                   3358:                args[ac++] = "--preallocate";
                   3359: 
1.1.1.4 ! misho    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: 
1.1       misho    3366:        if (ac > MAX_SERVER_ARGS) { /* Not possible... */
                   3367:                rprintf(FERROR, "argc overflow in server_options().\n");
                   3368:                exit_cleanup(RERR_MALLOC);
                   3369:        }
1.1.1.3   misho    3370: 
1.1.1.2   misho    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: 
1.1       misho    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: 
1.1.1.4 ! misho    3444: /* Look for a HOST specification of the form "HOST:PATH", "HOST::PATH", or
1.1       misho    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)
1.1.1.4 ! misho    3459:                                *port_ptr = -1; /* -1 indicates they want the default */
1.1       misho    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)
1.1.1.4 ! misho    3470:                        *port_ptr = -1;
1.1       misho    3471:                return path + 1;
                   3472:        }
                   3473:        if (port_ptr)
                   3474:                *port_ptr = 0;
                   3475: 
                   3476:        return path;
                   3477: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>