Clean generated files for distclean.
[rsync/rsync.git] / options.c
index 241d075..65fc9c4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -20,6 +20,7 @@
  */
 
 #include "rsync.h"
+#include "ifuncs.h"
 #include <popt.h>
 #include "zlib/zlib.h"
 
@@ -90,6 +91,7 @@ char *files_from = NULL;
 int filesfrom_fd = -1;
 char *filesfrom_host = NULL;
 int eol_nulls = 0;
+int protect_args = 0;
 int human_readable = 0;
 int recurse = 0;
 int allow_inc_recurse = 1;
@@ -183,8 +185,8 @@ int list_only = 0;
 #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
 char *batch_name = NULL;
 
-#ifdef ICONV_OPTION
 int need_unsorted_flist = 0;
+#ifdef ICONV_OPTION
 char *iconv_opt = ICONV_OPTION;
 #endif
 
@@ -349,7 +351,7 @@ void usage(enum logcode F)
   rprintf(F,"     --fake-super            store/recover privileged attrs using xattrs\n");
 #endif
   rprintf(F," -S, --sparse                handle sparse files efficiently\n");
-  rprintf(F," -n, --dry-run               show what would have been transferred\n");
+  rprintf(F," -n, --dry-run               perform a trial run with no changes made\n");
   rprintf(F," -W, --whole-file            copy files whole (without rsync algorithm)\n");
   rprintf(F," -x, --one-file-system       don't cross filesystem boundaries\n");
   rprintf(F," -B, --block-size=SIZE       force a fixed checksum block-size\n");
@@ -397,6 +399,7 @@ void usage(enum logcode F)
   rprintf(F,"     --include-from=FILE     read include patterns from FILE\n");
   rprintf(F,"     --files-from=FILE       read list of source-file names from FILE\n");
   rprintf(F," -0, --from0                 all *-from/filter files are delimited by 0s\n");
+  rprintf(F," -s, --protect-args          no space-splitting; only wildcard special-chars\n");
   rprintf(F,"     --address=ADDRESS       bind address for outgoing socket to daemon\n");
   rprintf(F,"     --port=PORT             specify double-colon alternate port number\n");
   rprintf(F,"     --sockopts=OPTIONS      specify custom TCP options\n");
@@ -418,7 +421,7 @@ void usage(enum logcode F)
   rprintf(F,"     --read-batch=FILE       read a batched update from FILE\n");
   rprintf(F,"     --protocol=NUM          force an older protocol version to be used\n");
 #ifdef ICONV_OPTION
-  rprintf(F,"     --iconv=CONVERT_SPEC    request charset conversion of filesnames\n");
+  rprintf(F,"     --iconv=CONVERT_SPEC    request charset conversion of filenames\n");
 #endif
   rprintf(F," -4, --ipv4                  prefer IPv4\n");
   rprintf(F," -6, --ipv6                  prefer IPv6\n");
@@ -459,8 +462,8 @@ static struct poptOption long_options[] = {
   {"no-r",             0,  POPT_ARG_VAL,    &recurse, 0, 0, 0 },
   {"inc-recursive",    0,  POPT_ARG_VAL,    &allow_inc_recurse, 1, 0, 0 },
   {"no-inc-recursive", 0,  POPT_ARG_VAL,    &allow_inc_recurse, 0, 0, 0 },
-  {"ir",               0,  POPT_ARG_VAL,    &allow_inc_recurse, 1, 0, 0 },
-  {"no-ir",            0,  POPT_ARG_VAL,    &allow_inc_recurse, 0, 0, 0 },
+  {"i-r",              0,  POPT_ARG_VAL,    &allow_inc_recurse, 1, 0, 0 },
+  {"no-i-r",           0,  POPT_ARG_VAL,    &allow_inc_recurse, 0, 0, 0 },
   {"dirs",            'd', POPT_ARG_VAL,    &xfer_dirs, 2, 0, 0 },
   {"no-dirs",          0,  POPT_ARG_VAL,    &xfer_dirs, 0, 0, 0 },
   {"no-d",             0,  POPT_ARG_VAL,    &xfer_dirs, 0, 0, 0 },
@@ -512,6 +515,8 @@ static struct poptOption long_options[] = {
   {"no-R",             0,  POPT_ARG_VAL,    &relative_paths, 0, 0, 0 },
   {"implied-dirs",     0,  POPT_ARG_VAL,    &implied_dirs, 1, 0, 0 },
   {"no-implied-dirs",  0,  POPT_ARG_VAL,    &implied_dirs, 0, 0, 0 },
+  {"i-d",              0,  POPT_ARG_VAL,    &implied_dirs, 1, 0, 0 },
+  {"no-i-d",           0,  POPT_ARG_VAL,    &implied_dirs, 0, 0, 0 },
   {"chmod",            0,  POPT_ARG_STRING, 0, OPT_CHMOD, 0, 0 },
   {"ignore-times",    'I', POPT_ARG_NONE,   &ignore_times, 0, 0, 0 },
   {"size-only",        0,  POPT_ARG_NONE,   &size_only, 0, 0, 0 },
@@ -591,6 +596,9 @@ static struct poptOption long_options[] = {
   {"files-from",       0,  POPT_ARG_STRING, &files_from, 0, 0, 0 },
   {"from0",           '0', POPT_ARG_VAL,    &eol_nulls, 1, 0, 0},
   {"no-from0",         0,  POPT_ARG_VAL,    &eol_nulls, 0, 0, 0},
+  {"protect-args",    's', POPT_ARG_VAL,    &protect_args, 1, 0, 0},
+  {"no-protect-args",  0,  POPT_ARG_VAL,    &protect_args, 0, 0, 0},
+  {"no-s",             0,  POPT_ARG_VAL,    &protect_args, 0, 0, 0},
   {"numeric-ids",      0,  POPT_ARG_VAL,    &numeric_ids, 1, 0, 0 },
   {"no-numeric-ids",   0,  POPT_ARG_VAL,    &numeric_ids, 0, 0, 0 },
   {"timeout",          0,  POPT_ARG_INT,    &io_timeout, 0, 0, 0 },
@@ -856,12 +864,13 @@ static void create_refuse_error(int which)
  *
  * @retval 0 on error, with err_buf containing an explanation
  **/
-int parse_arguments(int *argc, const char ***argv, int frommain)
+int parse_arguments(int *argc_p, const char ***argv_p, int frommain)
 {
-       int opt;
+       static poptContext pc;
        char *ref = lp_refuse_options(module_id);
-       const char *arg;
-       poptContext pc;
+       const char *arg, **argv = *argv_p;
+       int argc = *argc_p;
+       int opt;
 
        if (ref && *ref)
                set_refuse_options(ref);
@@ -869,7 +878,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                set_refuse_options("log-file*");
 
 #ifdef ICONV_OPTION
-       if (!am_daemon && (arg = getenv("RSYNC_ICONV")) != NULL && *arg)
+       if (!am_daemon && !protect_args && (arg = getenv("RSYNC_ICONV")) != NULL && *arg)
                iconv_opt = strdup(arg);
 #endif
 
@@ -877,8 +886,11 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
 
        /* The context leaks in case of an error, but if there's a
         * problem we always exit anyhow. */
-       pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
+       if (pc)
+               poptFreeContext(pc);
+       pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0);
+       if (!am_server)
+               poptReadDefaultConfig(pc, 0);
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
                /* most options are handled automatically by popt;
@@ -894,7 +906,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                                /* Disable popt aliases on the server side and
                                 * then start parsing the options again. */
                                poptFreeContext(pc);
-                               pc = poptGetContext(RSYNC_NAME, *argc, *argv,
+                               pc = poptGetContext(RSYNC_NAME, argc, argv,
                                                    long_options, 0);
                                am_server = 1;
                        }
@@ -922,7 +934,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        iconv_opt = NULL;
 #endif
                        poptFreeContext(pc);
-                       pc = poptGetContext(RSYNC_NAME, *argc, *argv,
+                       pc = poptGetContext(RSYNC_NAME, argc, argv,
                                            long_daemon_options, 0);
                        while ((opt = poptGetNextOpt(pc)) != -1) {
                                switch (opt) {
@@ -957,8 +969,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                                exit_cleanup(RERR_SYNTAX);
                        }
 
-                       *argv = poptGetArgs(pc);
-                       *argc = count_args(*argv);
+                       *argv_p = argv = poptGetArgs(pc);
+                       *argc_p = argc = count_args(argv);
                        am_starting_up = 0;
                        daemon_opt = 0;
                        am_daemon = 1;
@@ -991,15 +1003,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        if (sanitize_paths)
                                arg = sanitize_path(NULL, arg, NULL, 0, NULL);
                        if (server_filter_list.head) {
+                               int rej;
                                char *cp = strdup(arg);
                                if (!cp)
                                        out_of_memory("parse_arguments");
                                if (!*cp)
                                        goto options_rejected;
-                               clean_fname(cp, 1);
-                               if (check_filter(&server_filter_list, cp, 0) < 0)
-                                       goto options_rejected;
+                               clean_fname(cp, CFN_COLLAPSE_DOT_DOT_DIRS);
+                               rej = check_filter(&server_filter_list, cp, 0) < 0;
                                free(cp);
+                               if (rej)
+                                       goto options_rejected;
                        }
                        parse_filter_file(&filter_list, arg,
                                opt == OPT_INCLUDE_FROM ? MATCHFLG_INCLUDE : 0,
@@ -1186,9 +1200,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        break;
 #else
                        /* FIXME: this should probably be ignored with a
-                        * warning and then countermeasures taken to
-                        * restrict group and other access in the presence
-                        * of any more restrictive ACLs, but this is safe
+                        * warning and then countermeasures taken to
+                        * restrict group and other access in the presence
+                        * of any more restrictive ACLs, but this is safe
                         * for now */
                        snprintf(err_buf,sizeof(err_buf),
                                  "ACLs are not supported on this %s\n",
@@ -1222,14 +1236,14 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                }
        }
 
-       if (human_readable && *argc == 2) {
+       if (human_readable && argc == 2) {
                /* Allow the old meaning of 'h' (--help) on its own. */
                usage(FINFO);
                exit_cleanup(0);
        }
 
 #ifdef ICONV_OPTION
-       if (iconv_opt) {
+       if (iconv_opt && protect_args != 2) {
                if (!am_server && strcmp(iconv_opt, "-") == 0)
                        iconv_opt = NULL;
                else
@@ -1237,6 +1251,13 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
        }
 #endif
 
+       if (protect_args == 1) {
+               if (!frommain)
+                       protect_args = 0;
+               else if (am_server)
+                       return 1;
+       }
+
 #ifndef SUPPORT_LINKS
        if (preserve_links && !am_sender) {
                snprintf(err_buf, sizeof err_buf,
@@ -1367,13 +1388,13 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                need_messages_from_generator = 1;
        }
 
-       *argv = poptGetArgs(pc);
-       *argc = count_args(*argv);
+       *argv_p = argv = poptGetArgs(pc);
+       *argc_p = argc = count_args(argv);
 
        if (sanitize_paths) {
                int i;
-               for (i = *argc; i-- > 0; )
-                       (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0, NULL);
+               for (i = argc; i-- > 0; )
+                       argv[i] = sanitize_path(NULL, argv[i], "", 0, NULL);
                if (tmpdir)
                        tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, NULL);
                if (backup_dir)
@@ -1384,22 +1405,19 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                if (tmpdir) {
                        if (!*tmpdir)
                                goto options_rejected;
-                       clean_fname(tmpdir, 1);
+                       clean_fname(tmpdir, CFN_COLLAPSE_DOT_DOT_DIRS);
                        if (check_filter(elp, tmpdir, 1) < 0)
                                goto options_rejected;
                }
                if (backup_dir) {
                        if (!*backup_dir)
                                goto options_rejected;
-                       clean_fname(backup_dir, 1);
+                       clean_fname(backup_dir, CFN_COLLAPSE_DOT_DOT_DIRS);
                        if (check_filter(elp, backup_dir, 1) < 0)
                                goto options_rejected;
                }
        }
 
-       if (omit_dir_times && preserve_times > 1)
-               preserve_times = 1;
-
        if (!backup_suffix)
                backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
        backup_suffix_len = strlen(backup_suffix);
@@ -1427,13 +1445,20 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                snprintf(err_buf, sizeof err_buf,
                        "--suffix cannot be a null string without --backup-dir\n");
                return 0;
-       } else if (make_backups && delete_mode && !delete_excluded && !am_server) {
-               snprintf(backup_dir_buf, sizeof backup_dir_buf,
+       } else if (make_backups && delete_mode && !delete_excluded && !am_server) {
+               snprintf(backup_dir_buf, sizeof backup_dir_buf,
                        "P *%s", backup_suffix);
-               parse_rule(&filter_list, backup_dir_buf, 0, 0);
+               parse_rule(&filter_list, backup_dir_buf, 0, 0);
+       }
+
+       if (make_backups && !backup_dir) {
+               omit_dir_times = 0; /* Implied, so avoid -O to sender. */
+               if (preserve_times > 1)
+                       preserve_times = 1;
+       } else if (omit_dir_times) {
+               if (preserve_times > 1)
+                       preserve_times = 1;
        }
-       if (make_backups && !backup_dir && preserve_times > 1)
-               preserve_times = 1;
 
        if (stdout_format) {
                if (am_server && log_format_has(stdout_format, 'I'))
@@ -1540,7 +1565,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                }
                if (partial_dir) {
                        if (*partial_dir)
-                               clean_fname(partial_dir, 1);
+                               clean_fname(partial_dir, CFN_COLLAPSE_DOT_DOT_DIRS);
                        if (!*partial_dir || strcmp(partial_dir, ".") == 0)
                                partial_dir = NULL;
                        if (!partial_dir && refused_partial) {
@@ -1554,7 +1579,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
        if (files_from) {
                char *h, *p;
                int q;
-               if (*argc > 2 || (!am_daemon && *argc == 1)) {
+               if (argc > 2 || (!am_daemon && argc == 1)) {
                        usage(FERROR);
                        exit_cleanup(RERR_SYNTAX);
                }
@@ -1581,7 +1606,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        if (server_filter_list.head) {
                                if (!*files_from)
                                        goto options_rejected;
-                               clean_fname(files_from, 1);
+                               clean_fname(files_from, CFN_COLLAPSE_DOT_DOT_DIRS);
                                if (check_filter(&server_filter_list, files_from, 0) < 0)
                                        goto options_rejected;
                        }
@@ -1614,23 +1639,19 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
  * behave, and also filtering out options that are processed only
  * locally.
  **/
-void server_options(char **args,int *argc)
+void server_options(char **args, int *argc_p)
 {
        static char argstr[64];
-       int ac = *argc;
+       int ac = *argc_p;
        char *arg;
-
        int i, x;
 
-       if (blocking_io == -1)
-               blocking_io = 0;
-
        /* This should always remain first on the server's command-line. */
        args[ac++] = "--server";
 
        if (daemon_over_rsh > 0) {
                args[ac++] = "--daemon";
-               *argc = ac;
+               *argc_p = ac;
                /* if we're passing --daemon, we're done */
                return;
        }
@@ -1640,6 +1661,10 @@ void server_options(char **args,int *argc)
 
        x = 1;
        argstr[0] = '-';
+
+       if (protect_args)
+               argstr[x++] = 's';
+
        for (i = 0; i < verbose; i++)
                argstr[x++] = 'v';
 
@@ -1652,7 +1677,8 @@ void server_options(char **args,int *argc)
                argstr[x++] = 'n';
        if (preserve_links)
                argstr[x++] = 'l';
-       if (xfer_dirs > (recurse || !delete_mode || !am_sender ? 1 : 0))
+       if ((list_only && !recurse) || xfer_dirs > 1
+        || (xfer_dirs && !recurse && delete_mode && am_sender))
                argstr[x++] = 'd';
        if (am_sender) {
                if (keep_dirlinks)
@@ -1722,26 +1748,42 @@ void server_options(char **args,int *argc)
        if (do_compression)
                argstr[x++] = 'z';
 
-       /* This is a complete hack - blame Rusty.  FIXME!
-        * This hack is only needed for older rsync versions that
-        * don't understand the --list-only option. */
-       if (list_only == 1 && !recurse)
-               argstr[x++] = 'r';
-
+       /* We make use of the -e option to let the server know about any
+        * pre-release protocol version && our allow_inc_recurse status. */
+       set_allow_inc_recurse();
 #if SUBPROTOCOL_VERSION != 0
-       /* If we're speaking a pre-release version of a protocol, we tell
-        * the server about this by (ab)using the -e option. */
        if (protocol_version == PROTOCOL_VERSION) {
                x += snprintf(argstr+x, sizeof argstr - x,
-                             "e%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
-       }
+                             "e%d.%d%s", PROTOCOL_VERSION, SUBPROTOCOL_VERSION,
+                             allow_inc_recurse ? "i" : "");
+       } else
 #endif
+       if (allow_inc_recurse) {
+               argstr[x++] = 'e';
+               argstr[x++] = 'i';
+       }
 
        argstr[x] = '\0';
 
        if (x != 1)
                args[ac++] = argstr;
 
+#ifdef ICONV_OPTION
+       if (iconv_opt) {
+               char *set = strchr(iconv_opt, ',');
+               if (set)
+                       set++;
+               else
+                       set = iconv_opt;
+               if (asprintf(&arg, "--iconv=%s", set) < 0)
+                       goto oom;
+               args[ac++] = arg;
+       }
+#endif
+
+       if (protect_args) /* initial args break here */
+               args[ac++] = NULL;
+
        if (list_only > 1)
                args[ac++] = "--list-only";
 
@@ -1777,19 +1819,6 @@ void server_options(char **args,int *argc)
                        args[ac++] = "--log-format=X";
        }
 
-#ifdef ICONV_OPTION
-       if (iconv_opt) {
-               char *set = strchr(iconv_opt, ',');
-               if (set)
-                       set++;
-               else
-                       set = iconv_opt;
-               if (asprintf(&arg, "--iconv=%s", set) < 0)
-                       goto oom;
-               args[ac++] = arg;
-       }
-#endif
-
        if (block_size) {
                if (asprintf(&arg, "-B%lu", block_size) < 0)
                        goto oom;
@@ -1827,7 +1856,7 @@ void server_options(char **args,int *argc)
                                goto oom;
                        args[ac++] = arg;
                } else if (max_delete == 0)
-                       args[ac++] = "--max_delete=-1";
+                       args[ac++] = "--max-delete=-1";
                if (min_size) {
                        args[ac++] = "--min-size";
                        args[ac++] = min_size_arg;
@@ -1898,8 +1927,8 @@ void server_options(char **args,int *argc)
        if (numeric_ids)
                args[ac++] = "--numeric-ids";
 
-       if (!allow_inc_recurse)
-               args[ac++] = "--no-ir";
+       if (use_qsort)
+               args[ac++] = "--use-qsort";
 
        if (am_sender) {
                if (ignore_existing)
@@ -1947,7 +1976,8 @@ void server_options(char **args,int *argc)
                if (!relative_paths)
                        args[ac++] = "--no-relative";
        }
-       if (relative_paths && !implied_dirs && !am_sender)
+       /* It's OK that this checks the upper-bound of the protocol_version. */
+       if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30))
                args[ac++] = "--no-implied-dirs";
 
        if (fuzzy_basis && am_sender)
@@ -1958,7 +1988,7 @@ void server_options(char **args,int *argc)
        else if (remove_source_files)
                args[ac++] = "--remove-sent-files";
 
-       *argc = ac;
+       *argc_p = ac;
        return;
 
     oom: