Fixed the timeout/flush loop-check logic to work properly with
[rsync/rsync.git] / options.c
index f2d23f6..d534cec 100644 (file)
--- a/options.c
+++ b/options.c
@@ -174,6 +174,10 @@ int link_dest = 0;
 int basis_dir_cnt = 0;
 char *dest_option = NULL;
 
+static int remote_option_alloc = 0;
+int remote_option_cnt = 0;
+const char **remote_options = NULL;
+
 int verbose = 0;
 int quiet = 0;
 int output_motd = 1;
@@ -387,6 +391,7 @@ void usage(enum logcode F)
   rprintf(F,"     --timeout=SECONDS       set I/O timeout in seconds\n");
   rprintf(F,"     --contimeout=SECONDS    set daemon connection timeout in seconds\n");
   rprintf(F," -I, --ignore-times          don't skip files that match in size and mod-time\n");
+  rprintf(F," -M, --remote-option=OPTION  send OPTION to the remote side only\n");
   rprintf(F,"     --size-only             skip files that match in size\n");
   rprintf(F,"     --modify-window=NUM     compare mod-times with reduced accuracy\n");
   rprintf(F," -T, --temp-dir=DIR          create temporary files in directory DIR\n");
@@ -475,6 +480,8 @@ static struct poptOption long_options[] = {
   {"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 },
+  {"old-dirs",         0,  POPT_ARG_VAL,    &xfer_dirs, 4, 0, 0 },
+  {"old-d",            0,  POPT_ARG_VAL,    &xfer_dirs, 4, 0, 0 },
   {"perms",           'p', POPT_ARG_VAL,    &preserve_perms, 1, 0, 0 },
   {"no-perms",         0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
   {"no-p",             0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
@@ -643,6 +650,7 @@ static struct poptOption long_options[] = {
   {"password-file",    0,  POPT_ARG_STRING, &password_file, 0, 0, 0 },
   {"blocking-io",      0,  POPT_ARG_VAL,    &blocking_io, 1, 0, 0 },
   {"no-blocking-io",   0,  POPT_ARG_VAL,    &blocking_io, 0, 0, 0 },
+  {"remote-option",   'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
   {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
   {"checksum-seed",    0,  POPT_ARG_INT,    &checksum_seed, 0, 0, 0 },
   {"server",           0,  POPT_ARG_NONE,   0, OPT_SERVER, 0, 0 },
@@ -1042,7 +1050,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                                        goto options_rejected;
                                dir = cp + (*cp == '/' ? module_dirlen : 0);
                                clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
-                               rej = check_filter(&daemon_filter_list, dir, 0) < 0;
+                               rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0;
                                free(cp);
                                if (rej)
                                        goto options_rejected;
@@ -1138,6 +1146,26 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        }
                        break;
 
+               case 'M':
+                       arg = poptGetOptArg(pc);
+                       if (*arg != '-') {
+                               snprintf(err_buf, sizeof err_buf,
+                                       "Remote option must start with a dash: %s\n", arg);
+                               return 0;
+                       }
+                       if (remote_option_cnt+2 >= remote_option_alloc) {
+                               remote_option_alloc += 16;
+                               remote_options = realloc_array(remote_options,
+                                                       const char *, remote_option_alloc);
+                               if (!remote_options)
+                                       out_of_memory("parse_arguments");
+                               if (!remote_option_cnt)
+                                       remote_options[0] = "ARG0";
+                       }
+                       remote_options[++remote_option_cnt] = arg;
+                       remote_options[remote_option_cnt+1] = NULL;
+                       break;
+
                case OPT_WRITE_BATCH:
                        /* batch_name is already set */
                        write_batch = 1;
@@ -1273,7 +1301,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                }
        }
 
-       if (human_readable && argc == 2) {
+       if (human_readable && argc == 2 && !am_server) {
                /* Allow the old meaning of 'h' (--help) on its own. */
                usage(FINFO);
                exit_cleanup(0);
@@ -1295,6 +1323,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
        if (protect_args == 1 && am_server)
                return 1;
 
+       *argv_p = argv = poptGetArgs(pc);
+       *argc_p = argc = count_args(argv);
+
 #ifndef SUPPORT_LINKS
        if (preserve_links && !am_sender) {
                snprintf(err_buf, sizeof err_buf,
@@ -1382,8 +1413,16 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        xfer_dirs = 1;
        }
 
-       if (xfer_dirs < 1)
-               xfer_dirs = recurse || list_only;
+       if (argc < 2 && !read_batch && !am_server)
+               list_only |= 1;
+
+       if (xfer_dirs >= 4) {
+               parse_rule(&filter_list, "- /*/*", 0, 0);
+               recurse = xfer_dirs = 1;
+       } else if (recurse)
+               xfer_dirs = 1;
+       else if (xfer_dirs < 0)
+               xfer_dirs = list_only ? 1 : 0;
 
        if (relative_paths < 0)
                relative_paths = files_from? 1 : 0;
@@ -1432,9 +1471,6 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                need_messages_from_generator = 1;
        }
 
-       *argv_p = argv = poptGetArgs(pc);
-       *argc_p = argc = count_args(argv);
-
        if (sanitize_paths) {
                int i;
                for (i = argc; i-- > 0; )
@@ -1452,7 +1488,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                                goto options_rejected;
                        dir = tmpdir + (*tmpdir == '/' ? module_dirlen : 0);
                        clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
-                       if (check_filter(elp, dir, 1) < 0)
+                       if (check_filter(elp, FLOG, dir, 1) < 0)
                                goto options_rejected;
                }
                if (backup_dir) {
@@ -1461,7 +1497,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                                goto options_rejected;
                        dir = backup_dir + (*backup_dir == '/' ? module_dirlen : 0);
                        clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
-                       if (check_filter(elp, dir, 1) < 0)
+                       if (check_filter(elp, FLOG, dir, 1) < 0)
                                goto options_rejected;
                }
        }
@@ -1522,8 +1558,12 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                log_before_transfer = !am_server;
        }
 
-       if (do_progress && !verbose && !log_before_transfer && !am_server)
-               verbose = 1;
+       if (do_progress) {
+               if (am_server)
+                       do_progress = 0;
+               else if (!verbose && !log_before_transfer && !am_server)
+                       verbose = 1;
+       }
 
        if (dry_run)
                do_xfers = 0;
@@ -1657,7 +1697,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                                        goto options_rejected;
                                dir = files_from + (*files_from == '/' ? module_dirlen : 0);
                                clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS);
-                               if (check_filter(&daemon_filter_list, dir, 0) < 0)
+                               if (check_filter(&daemon_filter_list, FLOG, dir, 0) < 0)
                                        goto options_rejected;
                        }
                        filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
@@ -1727,8 +1767,8 @@ void server_options(char **args, int *argc_p)
                argstr[x++] = 'n';
        if (preserve_links)
                argstr[x++] = 'l';
-       if ((list_only && !recurse) || xfer_dirs > 1
-        || (xfer_dirs && !recurse && delete_mode && am_sender))
+       if ((xfer_dirs >= 2 && xfer_dirs < 4)
+        || (xfer_dirs && !recurse && (list_only || (delete_mode && am_sender))))
                argstr[x++] = 'd';
        if (am_sender) {
                if (keep_dirlinks)
@@ -1798,24 +1838,35 @@ void server_options(char **args, int *argc_p)
        if (do_compression)
                argstr[x++] = 'z';
 
-       /* We make use of the -e option to let the server know about any
-        * pre-release protocol version && some behavior flags. */
-       argstr[x++] = 'e';
+       set_allow_inc_recurse();
+
+       /* Checking the pre-negotiated value allows --protocol=29 override. */
+       if (protocol_version >= 30) {
+               /* We make use of the -e option to let the server know about
+                * any pre-release protocol version && some behavior flags. */
+               argstr[x++] = 'e';
 #if SUBPROTOCOL_VERSION != 0
-       if (protocol_version == PROTOCOL_VERSION) {
-               x += snprintf(argstr+x, sizeof argstr - x,
-                             "%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
-       } else
+               if (protocol_version == PROTOCOL_VERSION) {
+                       x += snprintf(argstr+x, sizeof argstr - x,
+                                     "%d.%d",
+                                     PROTOCOL_VERSION, SUBPROTOCOL_VERSION);
+               } else
 #endif
-               argstr[x++] = '.';
-       set_allow_inc_recurse();
-       if (allow_inc_recurse)
-               argstr[x++] = 'i';
+                       argstr[x++] = '.';
+               if (allow_inc_recurse)
+                       argstr[x++] = 'i';
 #if defined HAVE_LUTIMES && defined HAVE_UTIMES
-       argstr[x++] = 'L';
+               argstr[x++] = 'L';
 #endif
+       }
+
        argstr[x] = '\0';
 
+       if (x > (int)sizeof argstr) { /* Not possible... */
+               rprintf(FERROR, "argstr overflow in server_options().\n");
+               exit_cleanup(RERR_MALLOC);
+       }
+
        args[ac++] = argstr;
 
 #ifdef ICONV_OPTION
@@ -2038,6 +2089,21 @@ void server_options(char **args, int *argc_p)
        else if (remove_source_files)
                args[ac++] = "--remove-sent-files";
 
+       if (ac > MAX_SERVER_ARGS) { /* Not possible... */
+               rprintf(FERROR, "argc overflow in server_options().\n");
+               exit_cleanup(RERR_MALLOC);
+       }
+
+       if (remote_option_cnt) {
+               int j;
+               if (ac + remote_option_cnt > MAX_SERVER_ARGS) {
+                       rprintf(FERROR, "too many remote options specified.\n");
+                       exit_cleanup(RERR_SYNTAX);
+               }
+               for (j = 1; j <= remote_option_cnt; j++)
+                       args[ac++] = (char*)remote_options[j];
+       }
+
        *argc_p = ac;
        return;