Make idev, hlink and file_struct + strings use allocation
[rsync/rsync.git] / options.c
index b8c9f3d..5db7d62 100644 (file)
--- a/options.c
+++ b/options.c
@@ -46,27 +46,27 @@ int preserve_gid = 0;
 int preserve_times = 0;
 int update_only = 0;
 int cvs_exclude = 0;
-int dry_run=0;
-int local_server=0;
-int ignore_times=0;
-int delete_mode=0;
-int delete_excluded=0;
-int one_file_system=0;
+int dry_run = 0;
+int local_server = 0;
+int ignore_times = 0;
+int delete_mode = 0;
+int delete_excluded = 0;
+int one_file_system = 0;
 int protocol_version = PROTOCOL_VERSION;
-int sparse_files=0;
-int do_compression=0;
-int am_root=0;
-int orig_umask=0;
+int sparse_files = 0;
+int do_compression = 0;
+int am_root = 0;
+int orig_umask = 0;
 int relative_paths = -1;
 int implied_dirs = 1;
 int numeric_ids = 0;
 int force_delete = 0;
 int io_timeout = 0;
-int io_error = 0;
 int read_only = 0;
 int module_id = -1;
 int am_server = 0;
 int am_sender = 0;
+int am_generator = 0;
 char *files_from = NULL;
 int filesfrom_fd = -1;
 char *remote_filesfrom_file = NULL;
@@ -74,21 +74,22 @@ int eol_nulls = 0;
 int recurse = 0;
 int am_daemon = 0;
 int daemon_over_rsh = 0;
-int do_stats=0;
-int do_progress=0;
-int keep_partial=0;
-int safe_symlinks=0;
-int copy_unsafe_links=0;
-int block_size=0;
-int size_only=0;
-int bwlimit=0;
-int delete_after=0;
-int only_existing=0;
-int opt_ignore_existing=0;
-int max_delete=0;
-int ignore_errors=0;
-int modify_window=0;
-int blocking_io=-1;
+int do_stats = 0;
+int do_progress = 0;
+int keep_partial = 0;
+int safe_symlinks = 0;
+int copy_unsafe_links = 0;
+int size_only = 0;
+int bwlimit = 0;
+int delete_after = 0;
+int only_existing = 0;
+int opt_ignore_existing = 0;
+int max_delete = 0;
+int ignore_errors = 0;
+int modify_window = 0;
+int blocking_io = -1;
+int checksum_seed = 0;
+unsigned int block_size = 0;
 
 
 /** Network address family. **/
@@ -125,8 +126,11 @@ 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;
 
+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
@@ -162,11 +166,11 @@ static void print_rsync_version(enum logcode f)
        rprintf(f, "%s  version %s  protocol version %d\n",
                RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
        rprintf(f,
-               "Copyright (C) 1996-2002 by Andrew Tridgell and others\n");
+               "Copyright (C) 1996-2004 by Andrew Tridgell and others\n");
        rprintf(f, "<http://rsync.samba.org/>\n");
        rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
                "%shard links, %ssymlinks, batchfiles, \n",
-               (int) (sizeof(OFF_T) * 8),
+               (int) (sizeof (OFF_T) * 8),
                got_socketpair, hardlinks, links);
 
        /* Note that this field may not have type ino_t.  It depends
@@ -174,8 +178,8 @@ static void print_rsync_version(enum logcode f)
         * macros. */
        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 dumstat->st_ino * 8),
+               (int) (sizeof (INO64_T) * 8));
 #ifdef MAINTAINER_MODE
        rprintf(f, "              panic action: \"%s\"\n",
                get_panic_action());
@@ -219,14 +223,14 @@ void usage(enum logcode F)
   rprintf(F," -R, --relative              use relative path names\n");
   rprintf(F,"     --no-relative           turn off --relative\n");
   rprintf(F,"     --no-implied-dirs       don't send implied dirs with -R\n");
-  rprintf(F," -b, --backup                make backups (default %s suffix)\n",BACKUP_SUFFIX);
+  rprintf(F," -b, --backup                make backups (see --suffix & --backup-dir)\n");
   rprintf(F,"     --backup-dir            make backups into this directory\n");
-  rprintf(F,"     --suffix=SUFFIX         override backup suffix\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," -l, --links                 copy symlinks as symlinks\n");
-  rprintf(F," -L, --copy-links            copy the referent of symlinks\n");
-  rprintf(F,"     --copy-unsafe-links     copy links outside the source tree\n");
-  rprintf(F,"     --safe-links            ignore links outside the destination tree\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");
+  rprintf(F,"     --safe-links            ignore \"unsafe\" symlinks\n");
   rprintf(F," -H, --hard-links            preserve hard links\n");
   rprintf(F," -p, --perms                 preserve permissions\n");
   rprintf(F," -o, --owner                 preserve owner (root only)\n");
@@ -242,19 +246,19 @@ void usage(enum logcode F)
   rprintf(F," -e, --rsh=COMMAND           specify the remote shell\n");
   rprintf(F,"     --rsync-path=PATH       specify path to rsync on the remote machine\n");
   rprintf(F,"     --existing              only update files that already exist\n");
-  rprintf(F,"     --ignore-existing       ignore files that already exist on the receiving side\n");
+  rprintf(F,"     --ignore-existing       ignore files that already exist on receiving side\n");
   rprintf(F,"     --delete                delete files that don't exist on the sending side\n");
   rprintf(F,"     --delete-excluded       also delete excluded files on the receiving side\n");
-  rprintf(F,"     --delete-after          delete after transferring, not before\n");
-  rprintf(F,"     --ignore-errors         delete even if there are IO errors\n");
+  rprintf(F,"     --delete-after          receiver deletes after transferring, not before\n");
+  rprintf(F,"     --ignore-errors         delete even if there are I/O errors\n");
   rprintf(F,"     --max-delete=NUM        don't delete more than NUM files\n");
   rprintf(F,"     --partial               keep partially transferred files\n");
   rprintf(F,"     --force                 force deletion of directories even if not empty\n");
   rprintf(F,"     --numeric-ids           don't map uid/gid values by user/group name\n");
-  rprintf(F,"     --timeout=TIME          set IO timeout in seconds\n");
-  rprintf(F," -I, --ignore-times          don't exclude files that match length and time\n");
-  rprintf(F,"     --size-only             only use file size when determining if a file should be transferred\n");
-  rprintf(F,"     --modify-window=NUM     Timestamp window (seconds) for file match (default=%d)\n",modify_window);
+  rprintf(F,"     --timeout=TIME          set I/O timeout in seconds\n");
+  rprintf(F," -I, --ignore-times          turn off mod time & file size quick check\n");
+  rprintf(F,"     --size-only             ignore mod time for quick check (use 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");
   rprintf(F,"     --compare-dest=DIR      also compare destination files relative to DIR\n");
   rprintf(F,"     --link-dest=DIR         create hardlinks to DIR for unchanged files\n");
@@ -266,14 +270,14 @@ void usage(enum logcode F)
   rprintf(F,"     --include=PATTERN       don't exclude files matching PATTERN\n");
   rprintf(F,"     --include-from=FILE     don't exclude patterns listed in FILE\n");
   rprintf(F,"     --files-from=FILE       read FILE for list of source-file names\n");
-  rprintf(F," -0  --from0                 file names we read are separated by nulls, not newlines\n");
+  rprintf(F," -0  --from0                 all *-from file lists are delimited by nulls\n");
   rprintf(F,"     --version               print version number\n");
-  rprintf(F,"     --daemon                run as a rsync daemon\n");
+  rprintf(F,"     --daemon                run as an rsync daemon\n");
   rprintf(F,"     --no-detach             do not detach from the parent\n");
   rprintf(F,"     --address=ADDRESS       bind to the specified address\n");
   rprintf(F,"     --config=FILE           specify alternate rsyncd.conf file\n");
   rprintf(F,"     --port=PORT             specify alternate rsyncd port number\n");
-  rprintf(F,"     --blocking-io           use blocking IO for the remote shell\n");
+  rprintf(F,"     --blocking-io           use blocking I/O for the remote shell\n");
   rprintf(F,"     --no-blocking-io        turn off --blocking-io\n");
   rprintf(F,"     --stats                 give some file transfer stats\n");
   rprintf(F,"     --progress              show progress during transfer\n");
@@ -355,7 +359,7 @@ static struct poptOption long_options[] = {
   {"link-dest",        0,  POPT_ARG_STRING, 0,              OPT_LINK_DEST, 0, 0 },
   /* TODO: Should this take an optional int giving the compression level? */
   {"compress",        'z', POPT_ARG_NONE,   &do_compression, 0, 0, 0 },
-  {"daemon",           0,  POPT_ARG_NONE,   &am_daemon, 0, 0, 0 },
+  {"daemon",           0,  POPT_ARG_NONE,   &daemon_opt, 0, 0, 0 },
   {"no-detach",        0,  POPT_ARG_NONE,   &no_detach, 0, 0, 0 },
   {"stats",            0,  POPT_ARG_NONE,   &do_stats, 0, 0, 0 },
   {"progress",         0,  POPT_ARG_NONE,   &do_progress, 0, 0, 0 },
@@ -416,11 +420,13 @@ static int check_refuse_options(char *ref, int opt)
        char *p;
        const char *name;
 
-       for (i=0; long_options[i].longName; i++) {
-               if (long_options[i].val == opt) break;
+       for (i = 0; long_options[i].longName; i++) {
+               if (long_options[i].val == opt)
+                       break;
        }
 
-       if (!long_options[i].longName) return 0;
+       if (!long_options[i].longName)
+               return 0;
 
        name = long_options[i].longName;
        len = strlen(name);
@@ -428,7 +434,7 @@ static int check_refuse_options(char *ref, int opt)
        while ((p = strstr(ref,name))) {
                if ((p==ref || p[-1]==' ') &&
                    (p[len] == ' ' || p[len] == 0)) {
-                       snprintf(err_buf,sizeof(err_buf),
+                       snprintf(err_buf, sizeof err_buf,
                                 "The '%s' option is not supported by this server\n", name);
                        return 1;
                }
@@ -470,9 +476,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
        pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
-               if (ref) {
-                       if (check_refuse_options(ref, opt)) return 0;
-               }
+               if (ref && check_refuse_options(ref, opt))
+                       return 0;
 
                /* most options are handled automatically by popt;
                 * only special cases are returned and listed here. */
@@ -523,30 +528,13 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        usage(FINFO);
                        exit_cleanup(0);
 
-               case 'H':
-#if SUPPORT_HARD_LINKS
-                       preserve_hard_links=1;
-#else
-                       /* FIXME: Don't say "server" if this is
-                        * happening on the client. */
-                       /* FIXME: Why do we have the duplicated
-                        * rprintf?  Everybody who gets this message
-                        * ought to send it to the client and also to
-                        * the logs. */
-                       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 /* SUPPORT_HARD_LINKS */
-                       break;
-
                case 'v':
                        verbose++;
                        break;
 
                case 'q':
-                       if (frommain) quiet++;
+                       if (frommain)
+                               quiet++;
                        break;
 
                case OPT_SENDER:
@@ -565,11 +553,13 @@ 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_LINK_DEST:
@@ -587,9 +577,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
 
 
                default:
-                       /* FIXME: If --daemon is specified, then errors for later
-                        * parameters seem to disappear. */
-                       snprintf(err_buf, sizeof(err_buf),
+                       snprintf(err_buf, sizeof err_buf,
                                 "%s%s: %s\n",
                                 am_server ? "on remote machine: " : "",
                                 poptBadOption(pc, POPT_BADOPTION_NOALIAS),
@@ -598,11 +586,42 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                }
        }
 
+#if !SUPPORT_LINKS
+       if (preserve_links && !am_sender) {
+               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
+
+#if !SUPPORT_HARD_LINKS
+       if (preserve_hard_links) {
+               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
+
        if (write_batch && read_batch) {
                rprintf(FERROR,
                        "write-batch and read-batch can not be used together\n");
                exit_cleanup(RERR_SYNTAX);
        }
+       if (batch_prefix && strlen(batch_prefix) > MAX_BATCH_PREFIX_LEN) {
+               rprintf(FERROR,
+                       "the batch-file prefix must be %d characters or less.\n",
+                       MAX_BATCH_PREFIX_LEN);
+               exit_cleanup(RERR_SYNTAX);
+       }
+
+       if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
+               rprintf(FERROR, "the --temp-dir path is WAY too long.\n");
+               exit_cleanup(RERR_SYNTAX);
+       }
 
        if (do_compression && (write_batch || read_batch)) {
                rprintf(FERROR,
@@ -657,8 +676,11 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        usage(FERROR);
                        exit_cleanup(RERR_SYNTAX);
                }
-               if (strcmp(files_from, "-") == 0)
+               if (strcmp(files_from, "-") == 0) {
                        filesfrom_fd = 0;
+                       if (am_server)
+                               remote_filesfrom_file = "-";
+               }
                else if ((colon = find_colon(files_from)) != 0) {
                        if (am_server) {
                                usage(FERROR);
@@ -671,8 +693,10 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        }
                } else {
                        extern int sanitize_paths;
-                       if (sanitize_paths)
-                               sanitize_path(strdup(files_from), NULL);
+                       if (sanitize_paths) {
+                               files_from = strdup(files_from);
+                               sanitize_path(files_from, NULL);
+                       }
                        filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
                        if (filesfrom_fd < 0) {
                                rsyserr(FERROR, errno,
@@ -683,6 +707,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                }
        }
 
+       if (daemon_opt)
+               am_daemon = 1;
+
        return 1;
 }
 
@@ -699,13 +726,7 @@ void server_options(char **args,int *argc)
 {
        int ac = *argc;
        static char argstr[50];
-       static char bsize[30];
-       static char iotime[30];
-       static char mdelete[30];
-       static char mwindow[30];
-       static char bw[50];
-       /* Leave room for ``--(write|read)-batch='' */
-       static char fext[MAXPATHLEN + 15];
+       char *arg;
 
        int i, x;
 
@@ -726,7 +747,7 @@ void server_options(char **args,int *argc)
 
        x = 1;
        argstr[0] = '-';
-       for (i=0;i<verbose;i++)
+       for (i = 0; i < verbose; i++)
                argstr[x++] = 'v';
 
        /* the -q option is intentionally left out */
@@ -785,37 +806,38 @@ void server_options(char **args,int *argc)
 
        argstr[x] = 0;
 
-       if (x != 1) args[ac++] = argstr;
+       if (x != 1)
+               args[ac++] = argstr;
 
        if (block_size) {
-               snprintf(bsize,sizeof(bsize),"-B%d",block_size);
-               args[ac++] = bsize;
+               if (asprintf(&arg, "-B%u", block_size) < 0)
+                       goto oom;
+               args[ac++] = arg;
        }
 
        if (max_delete && am_sender) {
-               snprintf(mdelete,sizeof(mdelete),"--max-delete=%d",max_delete);
-               args[ac++] = mdelete;
+               if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
+                       goto oom;
+               args[ac++] = arg;
        }
 
-       if (batch_prefix != NULL) {
-               char *fmt = "";
-               if (write_batch)
-                       fmt = "--write-batch=%s";
-               else
-               if (read_batch)
-                       fmt = "--read-batch=%s";
-               snprintf(fext,sizeof(fext),fmt,batch_prefix);
-               args[ac++] = fext;
+       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) {
-               snprintf(iotime,sizeof(iotime),"--timeout=%d",io_timeout);
-               args[ac++] = iotime;
+               if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
+                       goto oom;
+               args[ac++] = arg;
        }
 
        if (bwlimit) {
-               snprintf(bw,sizeof(bw),"--bwlimit=%d",bwlimit);
-               args[ac++] = bw;
+               if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0)
+                       goto oom;
+               args[ac++] = arg;
        }
 
        if (backup_dir) {
@@ -824,28 +846,25 @@ void server_options(char **args,int *argc)
        }
 
        /* Only send --suffix if it specifies a non-default value. */
-       if (strcmp(backup_suffix, backup_dir? "" : BACKUP_SUFFIX) != 0) {
-               char *s = new_array(char, 9+backup_suffix_len+1);
-               if (!s)
-                       out_of_memory("server_options");
+       if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
                /* We use the following syntax to avoid weirdness with '~'. */
-               sprintf(s, "--suffix=%s", backup_suffix);
-               args[ac++] = s;
+               if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
+                       goto oom;
+               args[ac++] = arg;
        }
 
-       if (delete_mode && !delete_excluded)
-               args[ac++] = "--delete";
-
        if (delete_excluded)
                args[ac++] = "--delete-excluded";
+       else if (delete_mode)
+               args[ac++] = "--delete";
 
        if (size_only)
                args[ac++] = "--size-only";
 
        if (modify_window_set) {
-               snprintf(mwindow,sizeof(mwindow),"--modify-window=%d",
-                        modify_window);
-               args[ac++] = mwindow;
+               if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
+                       goto oom;
+               args[ac++] = arg;
        }
 
        if (keep_partial)
@@ -902,6 +921,10 @@ void server_options(char **args,int *argc)
        }
 
        *argc = ac;
+       return;
+
+    oom:
+       out_of_memory("server_options");
 }
 
 /**
@@ -913,12 +936,14 @@ char *find_colon(char *s)
        char *p, *p2;
 
        p = strchr(s,':');
-       if (!p) return NULL;
+       if (!p)
+               return NULL;
 
        /* now check to see if there is a / in the string before the : - if there is then
           discard the colon on the assumption that the : is part of a filename */
        p2 = strchr(s,'/');
-       if (p2 && p2 < p) return NULL;
+       if (p2 && p2 < p)
+               return NULL;
 
        return p;
 }