My modified version of Chris Shoemaker's improved batch-file handling.
[rsync/rsync.git] / options.c
index 6deafd0..d11e641 100644 (file)
--- a/options.c
+++ b/options.c
@@ -22,8 +22,9 @@
 #include "popt.h"
 
 extern int sanitize_paths;
+extern int select_timeout;
 extern char curr_dir[MAXPATHLEN];
-extern struct exclude_struct **exclude_list;
+extern struct exclude_list_struct exclude_list;
 
 int make_backups = 0;
 
@@ -38,6 +39,7 @@ int make_backups = 0;
 int whole_file = -1;
 
 int archive_mode = 0;
+int keep_dirlinks = 0;
 int copy_links = 0;
 int preserve_links = 0;
 int preserve_hard_links = 0;
@@ -83,6 +85,7 @@ int safe_symlinks = 0;
 int copy_unsafe_links = 0;
 int size_only = 0;
 int bwlimit = 0;
+size_t bwlimit_writemax = 0;
 int delete_after = 0;
 int only_existing = 0;
 int opt_ignore_existing = 0;
@@ -130,7 +133,6 @@ int quiet = 0;
 int always_checksum = 0;
 int list_only = 0;
 
-#define FIXED_CHECKSUM_SEED 32761
 #define MAX_BATCH_PREFIX_LEN 256       /* Must be less than MAXPATHLEN-13 */
 char *batch_prefix = NULL;
 
@@ -138,7 +140,7 @@ static int daemon_opt;   /* sets am_daemon after option error-reporting */
 static int modify_window_set;
 
 /** Local address to bind.  As a character string because it's
- * interpreted by the IPv6 layer: should be a numeric IP4 or ip6
+ * interpreted by the IPv6 layer: should be a numeric IP4 or IP6
  * address, or a hostname. **/
 char *bind_address;
 
@@ -183,7 +185,7 @@ static void print_rsync_version(enum logcode f)
        rprintf(f, "              %sIPv6, %d-bit system inums, %d-bit internal inums\n",
                ipv6,
                (int) (sizeof dumstat->st_ino * 8),
-               (int) (sizeof (INO64_T) * 8));
+               (int) (sizeof (uint64) * 8));
 #ifdef MAINTAINER_MODE
        rprintf(f, "              panic action: \"%s\"\n",
                get_panic_action());
@@ -231,6 +233,7 @@ void usage(enum logcode F)
   rprintf(F,"     --backup-dir            make backups into this directory\n");
   rprintf(F,"     --suffix=SUFFIX         backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
   rprintf(F," -u, --update                update only (don't overwrite newer files)\n");
+  rprintf(F," -K, --keep-dirlinks         treat symlinked dir on receiver as dir\n");
   rprintf(F," -l, --links                 copy symlinks as symlinks\n");
   rprintf(F," -L, --copy-links            copy the referent of all symlinks\n");
   rprintf(F,"     --copy-unsafe-links     copy the referent of \"unsafe\" symlinks\n");
@@ -290,11 +293,12 @@ void usage(enum logcode F)
   rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth, KBytes per second\n");
   rprintf(F,"     --write-batch=PREFIX    write batch fileset starting with PREFIX\n");
   rprintf(F,"     --read-batch=PREFIX     read batch fileset starting with PREFIX\n");
-  rprintf(F," -h, --help                  show this help screen\n");
+  rprintf(F,"     --checksum-seed=NUM     set block/file checksum seed\n");
 #ifdef INET6
-  rprintf(F," -4                          prefer IPv4\n");
-  rprintf(F," -6                          prefer IPv6\n");
+  rprintf(F," -4  --ipv4                  prefer IPv4\n");
+  rprintf(F," -6  --ipv6                  prefer IPv6\n");
 #endif
+  rprintf(F," -h, --help                  show this help screen\n");
 
   rprintf(F,"\n");
 
@@ -305,15 +309,15 @@ void usage(enum logcode F)
 enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
       OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
-      OPT_READ_BATCH, OPT_WRITE_BATCH,
+      OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT,
       OPT_REFUSED_BASE = 9000};
 
 static struct poptOption long_options[] = {
   /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
   {"version",          0,  POPT_ARG_NONE,   0,              OPT_VERSION, 0, 0},
   {"suffix",           0,  POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
-  {"rsync-path",       0,  POPT_ARG_STRING, &rsync_path,       0, 0, 0 },
-  {"password-file",    0,  POPT_ARG_STRING, &password_file,    0, 0, 0 },
+  {"rsync-path",       0,  POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
+  {"password-file",    0,  POPT_ARG_STRING, &password_file, 0, 0, 0 },
   {"ignore-times",    'I', POPT_ARG_NONE,   &ignore_times, 0, 0, 0 },
   {"size-only",        0,  POPT_ARG_NONE,   &size_only, 0, 0, 0 },
   {"modify-window",    0,  POPT_ARG_INT,    &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
@@ -336,6 +340,7 @@ static struct poptOption long_options[] = {
   {"sparse",          'S', POPT_ARG_NONE,   &sparse_files, 0, 0, 0 },
   {"cvs-exclude",     'C', POPT_ARG_NONE,   &cvs_exclude, 0, 0, 0 },
   {"update",          'u', POPT_ARG_NONE,   &update_only, 0, 0, 0 },
+  {"keep-dirlinks",   'K', POPT_ARG_NONE,   &keep_dirlinks, 0, 0, 0 },
   {"links",           'l', POPT_ARG_NONE,   &preserve_links, 0, 0, 0 },
   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links, 0, 0, 0 },
   {"whole-file",      'W', POPT_ARG_VAL,    &whole_file, 1, 0, 0 },
@@ -358,7 +363,7 @@ static struct poptOption long_options[] = {
   {"rsh",             'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
   {"block-size",      'B', POPT_ARG_INT,    &block_size, 0, 0, 0 },
   {"max-delete",       0,  POPT_ARG_INT,    &max_delete, 0, 0, 0 },
-  {"timeout",          0,  POPT_ARG_INT,    &io_timeout, 0, 0, 0 },
+  {"timeout",          0,  POPT_ARG_INT,    &io_timeout, OPT_TIMEOUT, 0, 0 },
   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
   {"compare-dest",     0,  POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
   {"link-dest",        0,  POPT_ARG_STRING, &compare_dest,  OPT_LINK_DEST, 0, 0 },
@@ -386,15 +391,16 @@ static struct poptOption long_options[] = {
   {"from0",           '0', POPT_ARG_NONE,   &eol_nulls, 0, 0, 0},
   {"no-implied-dirs",  0,  POPT_ARG_VAL,    &implied_dirs, 0, 0, 0 },
   {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
+  {"checksum-seed",    0,  POPT_ARG_INT,    &checksum_seed, 0, 0, 0 },
 #ifdef INET6
-  {0,                '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
-  {0,                '6', POPT_ARG_VAL,    &default_af_hint, AF_INET6, 0, 0 },
+  {"ipv4",            '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
+  {"ipv6",            '6', POPT_ARG_VAL,    &default_af_hint, AF_INET6, 0, 0 },
 #endif
   {0,0,0,0, 0, 0, 0}
 };
 
 
-static char err_buf[100];
+static char err_buf[200];
 
 
 /**
@@ -404,15 +410,12 @@ static char err_buf[100];
  **/
 void option_error(void)
 {
-       if (err_buf[0]) {
-               rprintf(FLOG, "%s", err_buf);
-               rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
-       } else {
-               rprintf (FERROR, "Error parsing options: "
-                        "option may be supported on client but not on server?\n");
-               rprintf (FERROR, RSYNC_NAME ": Error parsing options: "
-                        "option may be supported on client but not on server?\n");
+       if (!err_buf[0]) {
+               strcpy(err_buf, "Error parsing options: "
+                   "option may be supported on client but not on server?\n");
        }
+
+       rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
 }
 
 
@@ -510,29 +513,32 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        break;
 
                case OPT_EXCLUDE:
-                       add_exclude(&exclude_list, poptGetOptArg(pc),
-                                   ADD_EXCLUDE);
+                       if (am_server || sanitize_paths)
+                               return 0; /* Impossible... */
+                       add_exclude(&exclude_list, poptGetOptArg(pc), 0);
                        break;
 
                case OPT_INCLUDE:
+                       if (am_server || sanitize_paths)
+                               return 0; /* Impossible... */
                        add_exclude(&exclude_list, poptGetOptArg(pc),
-                                   ADD_INCLUDE);
+                                   XFLG_DEF_INCLUDE);
                        break;
 
                case OPT_EXCLUDE_FROM:
+                       if (am_server || sanitize_paths)
+                               return 0; /* Impossible... */
                        arg = poptGetOptArg(pc);
-                       if (sanitize_paths)
-                               arg = alloc_sanitize_path(arg, curr_dir);
                        add_exclude_file(&exclude_list, arg,
-                                        MISSING_FATAL, ADD_EXCLUDE);
+                                        XFLG_FATAL_ERRORS);
                        break;
 
                case OPT_INCLUDE_FROM:
+                       if (am_server || sanitize_paths)
+                               return 0; /* Impossible... */
                        arg = poptGetOptArg(pc);
-                       if (sanitize_paths)
-                               arg = alloc_sanitize_path(arg, curr_dir);
                        add_exclude_file(&exclude_list, arg,
-                                        MISSING_FATAL, ADD_INCLUDE);
+                                        XFLG_FATAL_ERRORS | XFLG_DEF_INCLUDE);
                        break;
 
                case 'h':
@@ -564,13 +570,16 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                case OPT_WRITE_BATCH:
                        /* popt stores the filename in batch_prefix for us */
                        write_batch = 1;
-                       checksum_seed = FIXED_CHECKSUM_SEED;
                        break;
 
                case OPT_READ_BATCH:
                        /* popt stores the filename in batch_prefix for us */
                        read_batch = 1;
-                       checksum_seed = FIXED_CHECKSUM_SEED;
+                       break;
+
+               case OPT_TIMEOUT:
+                       if (io_timeout && io_timeout < select_timeout)
+                               select_timeout = io_timeout;
                        break;
 
                case OPT_LINK_DEST:
@@ -581,7 +590,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        snprintf(err_buf, sizeof err_buf,
                                 "hard links are not supported on this %s\n",
                                 am_server ? "server" : "client");
-                       rprintf(FERROR, "ERROR: %s", err_buf);
                        return 0;
 #endif
 
@@ -614,7 +622,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                snprintf(err_buf, sizeof err_buf,
                         "symlinks are not supported on this %s\n",
                         am_server ? "server" : "client");
-               rprintf(FERROR, "ERROR: %s", err_buf);
                return 0;
        }
 #endif
@@ -624,7 +631,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                snprintf(err_buf, sizeof err_buf,
                         "hard links are not supported on this %s\n",
                         am_server ? "server" : "client");
-               rprintf(FERROR, "ERROR: %s", err_buf);
                return 0;
        }
 #endif
@@ -634,6 +640,14 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        "write-batch and read-batch can not be used together\n");
                exit_cleanup(RERR_SYNTAX);
        }
+       if ((write_batch || read_batch) && am_server) {
+               rprintf(FERROR,
+                       "batch-mode is incompatible with server mode\n");
+               /* We don't actually exit_cleanup(), so that we can still service
+                * older version clients that still send batch args to server. */
+               read_batch = write_batch = 0;
+               batch_prefix = NULL;
+       }
        if (batch_prefix && strlen(batch_prefix) > MAX_BATCH_PREFIX_LEN) {
                rprintf(FERROR,
                        "the batch-file prefix must be %d characters or less.\n",
@@ -646,12 +660,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                exit_cleanup(RERR_SYNTAX);
        }
 
-       if (do_compression && (write_batch || read_batch)) {
-               rprintf(FERROR,
-                       "compress can not be used with write-batch or read-batch\n");
-               exit_cleanup(RERR_SYNTAX);
-       }
-
        if (archive_mode) {
                if (!files_from)
                        recurse = 1;
@@ -688,6 +696,12 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        files_from = alloc_sanitize_path(files_from, curr_dir);
        }
 
+       if (daemon_opt) {
+               daemon_opt = 0;
+               am_daemon = 1;
+               return 1;
+       }
+
        if (!backup_suffix)
                backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
        backup_suffix_len = strlen(backup_suffix);
@@ -707,9 +721,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        backup_dir_buf[backup_dir_len++] = '/';
                        backup_dir_buf[backup_dir_len] = '\0';
                }
-               if (verbose > 1)
+               if (verbose > 1 && !am_sender)
                        rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
-       } else if (!backup_suffix_len) {
+       } else if (!backup_suffix_len && (!am_server || !am_sender)) {
                rprintf(FERROR,
                        "--suffix cannot be a null string without --backup-dir\n");
                exit_cleanup(RERR_SYNTAX);
@@ -718,9 +732,15 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
        if (do_progress && !verbose)
                verbose = 1;
 
+       if (bwlimit) {
+               bwlimit_writemax = (size_t)bwlimit * 128;
+               if (bwlimit_writemax < 512)
+                       bwlimit_writemax = 512;
+       }
+
        if (files_from) {
                char *colon;
-               if (*argc != 2) {
+               if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
                        usage(FERROR);
                        exit_cleanup(RERR_SYNTAX);
                }
@@ -750,9 +770,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                }
        }
 
-       if (daemon_opt)
-               am_daemon = 1;
-
        return 1;
 }
 
@@ -804,6 +821,8 @@ void server_options(char **args,int *argc)
                argstr[x++] = 'l';
        if (copy_links)
                argstr[x++] = 'L';
+       if (keep_dirlinks && am_sender)
+               argstr[x++] = 'K';
 
        if (whole_file > 0)
                argstr[x++] = 'W';
@@ -864,13 +883,6 @@ void server_options(char **args,int *argc)
                args[ac++] = arg;
        }
 
-       if (batch_prefix) {
-               char *r_or_w = write_batch ? "write" : "read";
-               if (asprintf(&arg, "--%s-batch=%s", r_or_w, batch_prefix) < 0)
-                       goto oom;
-               args[ac++] = arg;
-       }
-
        if (io_timeout) {
                if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
                        goto oom;
@@ -910,6 +922,12 @@ void server_options(char **args,int *argc)
                args[ac++] = arg;
        }
 
+       if (checksum_seed) {
+               if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
+                       goto oom;
+               args[ac++] = arg;
+       }
+
        if (keep_partial)
                args[ac++] = "--partial";