Must use STRUCT_STAT not "struct stat" to be compatible with other
[rsync.git] / options.c
index e6722623d58f924e4a40bb6e4e28efec6039304f..6a73e3c6f3b634a15096a8233559f8e4991237f9 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1,7 +1,7 @@
 /*  -*- c-file-style: "linux" -*-
     
     Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
-    Copyright (C) 2000-2001 by Martin Pool <mbp@samba.org>
+    Copyright (C) 2000, 2001, 2002 by Martin Pool <mbp@samba.org>
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 #include "popt.h"
 
 int make_backups = 0;
-int whole_file = 0;
+int whole_file = -1;
 int copy_links = 0;
 int preserve_links = 0;
 int preserve_hard_links = 0;
@@ -52,7 +52,7 @@ int io_error = 0;
 int read_only = 0;
 int module_id = -1;
 int am_server = 0;
-int am_sender=0;
+int am_sender = 0;
 int recurse = 0;
 int am_daemon=0;
 int do_stats=0;
@@ -65,6 +65,7 @@ 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;
 #ifdef _WIN32
@@ -72,10 +73,22 @@ int modify_window=2;
 #else
 int modify_window=0;
 #endif
-int blocking_io=0;
+int blocking_io=-1;
 
-int read_batch=0;  /* dw */
-int write_batch=0; /* dw */
+/** Network address family. **/
+#ifdef INET6
+int default_af_hint = 0;       /* Any protocol */
+#else
+int default_af_hint = AF_INET; /* Must use IPv4 */
+#endif
+
+/** Do not go into the background when run as --daemon.  Good
+ * for debugging and required for running as a service on W32,
+ * or under Unix process-monitors. **/
+int no_detach = 0;
+
+int write_batch = 0;
+int read_batch = 0;
 
 char *backup_suffix = BACKUP_SUFFIX;
 char *tmpdir = NULL;
@@ -93,19 +106,23 @@ int quiet = 0;
 int always_checksum = 0;
 int list_only = 0;
 
-char *batch_ext = NULL;
+char *batch_prefix = NULL;
 
 static int modify_window_set;
 
-
-struct in_addr socket_address = {INADDR_ANY};
+/** Local address to bind.  As a character string because it's
+ * interpreted by the IPv6 layer: should be a numeric IP4 or ip6
+ * address, or a hostname. **/
+char *bind_address;
 
 
-static void print_rsync_version(int f)
+static void print_rsync_version(enum logcode f)
 {
         char const *got_socketpair = "no ";
         char const *hardlinks = "no ";
         char const *links = "no ";
+       char const *ipv6 = "no ";
+       STRUCT_STAT *dumstat;
 
 #ifdef HAVE_SOCKETPAIR
         got_socketpair = "";
@@ -119,16 +136,26 @@ static void print_rsync_version(int f)
         links = "";
 #endif
 
+#if INET6
+       ipv6 = "";
+#endif       
+
         rprintf(f, "%s  version %s  protocol version %d\n",
-                RSYNC_NAME, VERSION, PROTOCOL_VERSION);
+                RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
         rprintf(f,
-                "Copyright (C) 1996-2001 by Andrew Tridgell, Paul Mackerras and others\n");
+                "Copyright (C) 1996-2002 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\n",
-                sizeof(int64) * 8,
-                got_socketpair,
-                hardlinks, links);
+                "%shard links, %ssymlinks, batchfiles, %sIPv6,\n",
+                (int) (sizeof(OFF_T) * 8),
+                got_socketpair, hardlinks, links, ipv6);
+
+       /* Note that this field may not have type ino_t.  It depends
+        * on the complicated interaction between largefile feature
+        * macros. */
+       rprintf(f, "              %d-bit system inums, %d-bit internal inums\n",
+               (int) (sizeof(dumstat->st_ino) * 8),
+               (int) (sizeof(INO64_T) * 8));
 
 #ifdef NO_INT64
         rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
@@ -162,8 +189,8 @@ void usage(enum logcode F)
   rprintf(F,"     --backup-dir            make backups into this directory\n");
   rprintf(F,"     --suffix=SUFFIX         override backup suffix\n");  
   rprintf(F," -u, --update                update only (don't overwrite newer files)\n");
-  rprintf(F," -l, --links                 preserve soft links\n");
-  rprintf(F," -L, --copy-links            treat soft links like regular 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," -H, --hard-links            preserve hard links\n");
@@ -175,12 +202,14 @@ void usage(enum logcode F)
   rprintf(F," -S, --sparse                handle sparse files efficiently\n");
   rprintf(F," -n, --dry-run               show what would have been transferred\n");
   rprintf(F," -W, --whole-file            copy whole files, no incremental checks\n");
+  rprintf(F,"     --no-whole-file         turn off --whole-file\n");
   rprintf(F," -x, --one-file-system       don't cross filesystem boundaries\n");
   rprintf(F," -B, --block-size=SIZE       checksum blocking size (default %d)\n",BLOCK_SIZE);  
   rprintf(F," -e, --rsh=COMMAND           specify rsh replacement\n");
   rprintf(F,"     --rsync-path=PATH       specify path to rsync on the remote machine\n");
   rprintf(F," -C, --cvs-exclude           auto ignore files in the same way CVS does\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,"     --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");
@@ -203,18 +232,24 @@ void usage(enum logcode F)
   rprintf(F,"     --include-from=FILE     don't exclude patterns listed in FILE\n");
   rprintf(F,"     --version               print version number\n");  
   rprintf(F,"     --daemon                run as a rsync daemon\n");  
-  rprintf(F,"     --address               bind to the specified address\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,"     --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");  
   rprintf(F,"     --log-format=FORMAT     log file transfers using specified format\n");  
   rprintf(F,"     --password-file=FILE    get password from FILE\n");
   rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth, KBytes per second\n");
-  rprintf(F," -f  --read-batch=EXT        read batch file\n");
-  rprintf(F," -F  --write-batch           write batch file\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");
+#ifdef INET6
+  rprintf(F," -4                          prefer IPv4\n");
+  rprintf(F," -6                          prefer IPv6\n");
+#endif
 
   rprintf(F,"\n");
 
@@ -230,7 +265,8 @@ enum {OPT_VERSION = 1000, OPT_SUFFIX, OPT_SENDER, OPT_SERVER, OPT_EXCLUDE,
       OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS,
       OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR, 
       OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO,
-      OPT_MODIFY_WINDOW};
+      OPT_NO_BLOCKING_IO, OPT_NO_WHOLE_FILE,
+      OPT_MODIFY_WINDOW, OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_IGNORE_EXISTING};
 
 static struct poptOption long_options[] = {
   /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
@@ -244,6 +280,7 @@ static struct poptOption long_options[] = {
   {"one-file-system", 'x', POPT_ARG_NONE,   &one_file_system},
   {"delete",           0,  POPT_ARG_NONE,   &delete_mode},
   {"existing",         0,  POPT_ARG_NONE,   &only_existing},
+  {"ignore-existing",  0,  POPT_ARG_NONE,   &opt_ignore_existing},
   {"delete-after",     0,  POPT_ARG_NONE,   &delete_after},
   {"delete-excluded",  0,  POPT_ARG_NONE,   0,              OPT_DELETE_EXCLUDED},
   {"force",            0,  POPT_ARG_NONE,   &force_delete},
@@ -261,7 +298,8 @@ static struct poptOption long_options[] = {
   {"update",          'u', POPT_ARG_NONE,   &update_only},
   {"links",           'l', POPT_ARG_NONE,   &preserve_links},
   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links},
-  {"whole",           'W', POPT_ARG_NONE,   &whole_file},
+  {"whole-file",      'W', POPT_ARG_NONE,   &whole_file},
+  {"no-whole-file",    0,  POPT_ARG_NONE,   0,                      OPT_NO_WHOLE_FILE},
   {"copy-unsafe-links", 0, POPT_ARG_NONE,   &copy_unsafe_links},
   {"perms",           'p', POPT_ARG_NONE,   &preserve_perms},
   {"owner",           'o', POPT_ARG_NONE,   &preserve_uid},
@@ -274,46 +312,58 @@ static struct poptOption long_options[] = {
   {"archive",         'a', POPT_ARG_NONE,   0,               'a'}, 
   {"server",           0,  POPT_ARG_NONE,   &am_server},
   {"sender",           0,  POPT_ARG_NONE,   0,               OPT_SENDER},
-  {"recurse",         'r', POPT_ARG_NONE,   &recurse},
+  {"recursive",       'r', POPT_ARG_NONE,   &recurse},
   {"relative",        'R', POPT_ARG_NONE,   &relative_paths},
   {"rsh",             'e', POPT_ARG_STRING, &shell_cmd},
   {"block-size",      'B', POPT_ARG_INT,    &block_size},
   {"max-delete",       0,  POPT_ARG_INT,    &max_delete},
   {"timeout",          0,  POPT_ARG_INT,    &io_timeout},
   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir},
-  {"compare-dest",     0,  POPT_ARG_NONE,   &compare_dest},
+  {"compare-dest",     0,  POPT_ARG_STRING, &compare_dest},
   /* TODO: Should this take an optional int giving the compression level? */
   {"compress",        'z', POPT_ARG_NONE,   &do_compression},
   {"daemon",           0,  POPT_ARG_NONE,   &am_daemon},
+  {"no-detach",        0,  POPT_ARG_NONE,   &no_detach},
   {"stats",            0,  POPT_ARG_NONE,   &do_stats},
   {"progress",         0,  POPT_ARG_NONE,   &do_progress},
   {"partial",          0,  POPT_ARG_NONE,   &keep_partial},
   {"ignore-errors",    0,  POPT_ARG_NONE,   &ignore_errors},
   {"blocking-io",      0,  POPT_ARG_NONE,   &blocking_io},
+  {"no-blocking-io",   0,  POPT_ARG_NONE,   0,                      OPT_NO_BLOCKING_IO},
   {0,                 'P', POPT_ARG_NONE,   0,               'P'},
   {"config",           0,  POPT_ARG_STRING, &config_file},
   {"port",             0,  POPT_ARG_INT,    &rsync_port},
   {"log-format",       0,  POPT_ARG_STRING, &log_format},
   {"bwlimit",          0,  POPT_ARG_INT,    &bwlimit},
-  {"address",          0,  POPT_ARG_STRING, 0,               OPT_ADDRESS},
+  {"address",          0,  POPT_ARG_STRING, &bind_address, 0},
   {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir},
   {"hard-links",      'H', POPT_ARG_NONE,   &preserve_hard_links},
-  {"read-batch",      'f', POPT_ARG_STRING, &batch_ext, 'f'},
-  {"write-batch",     'F', POPT_ARG_NONE,   &write_batch, 0},
+  {"read-batch",       0,  POPT_ARG_STRING, &batch_prefix, OPT_READ_BATCH},
+  {"write-batch",      0,  POPT_ARG_STRING, &batch_prefix, OPT_WRITE_BATCH},
+#ifdef INET6
+  {0,                '4', POPT_ARG_VAL,    &default_af_hint,   AF_INET },
+  {0,                '6', POPT_ARG_VAL,    &default_af_hint,   AF_INET6 },
+#endif
   {0,0,0,0}
 };
 
+
 static char err_buf[100];
 
 
+/* We store the option error message, if any, so that we can log the
+   connection attempt (which requires parsing the options), and then
+   show the error later on. */
 void option_error(void)
 {
        if (err_buf[0]) {
                rprintf(FLOG, "%s", err_buf);
                rprintf(FERROR, "%s: %s", RSYNC_NAME, err_buf);
        } else {
-               rprintf(FLOG,"Error parsing options - unsupported option?\n");
-               rprintf(FERROR,"Error parsing options - unsupported option?\n");
+               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");
        }
 }
 
@@ -409,8 +459,12 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        add_exclude_file(poptGetOptArg(pc), 1, 0);
                        break;
 
-               case OPT_INCLUDE_FROM:
-                       add_exclude_file(poptGetOptArg(pc), 1, 1);
+               case OPT_NO_WHOLE_FILE:
+                       whole_file = 0;
+                       break;
+
+               case OPT_NO_BLOCKING_IO:
+                       blocking_io = 0;
                        break;
 
                case 'h':
@@ -468,17 +522,13 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        keep_partial = 1;
                        break;
 
-               case OPT_ADDRESS:
-                       {
-                               struct in_addr *ia;
-                               if ((ia = ip_address(optarg))) {
-                                       socket_address = *ia;
-                               }
-                       }
+               case OPT_WRITE_BATCH:
+                       /* popt stores the filename in batch_prefix for us */
+                       write_batch = 1;
                        break;
 
-               case 'f':
-                       /* The filename is stored for us by popt */
+               case OPT_READ_BATCH:
+                       /* popt stores the filename in batch_prefix for us */
                        read_batch = 1;
                        break;
 
@@ -494,6 +544,22 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                }
        }
 
+       if (write_batch && read_batch) {
+           snprintf(err_buf,sizeof(err_buf),
+               "write-batch and read-batch can not be used together\n");
+           rprintf(FERROR,"ERROR: write-batch and read-batch"
+               " can not be used together\n");
+           return 0;
+       }
+
+       if (do_compression && (write_batch || read_batch)) {
+           snprintf(err_buf,sizeof(err_buf),
+               "compress can not be used with write-batch or read-batch\n");
+           rprintf(FERROR,"ERROR: compress can not be used with"
+               "  write-batch or read-batch\n");
+           return 0;
+       }
+
         *argv = poptGetArgs(pc);
         if (*argv)
                 *argc = count_args(*argv);
@@ -515,10 +581,16 @@ void server_options(char **args,int *argc)
        static char mdelete[30];
        static char mwindow[30];
        static char bw[50];
-       static char fext[20]; /* dw */
+       /* Leave room for ``--(write|read)-batch='' */
+       static char fext[MAXPATHLEN + 15];
 
        int i, x;
 
+       if (whole_file == -1)
+               whole_file = 0;
+       if (blocking_io == -1)
+               blocking_io = 0;
+
        args[ac++] = "--server";
 
        if (!am_sender)
@@ -570,8 +642,6 @@ void server_options(char **args,int *argc)
                argstr[x++] = 'S';
        if (do_compression)
                argstr[x++] = 'z';
-       if (write_batch)
-           argstr[x++] = 'F'; /* dw */
 
        /* this is a complete hack - blame Rusty 
 
@@ -594,8 +664,14 @@ void server_options(char **args,int *argc)
                args[ac++] = mdelete;
        }    
        
-       if (batch_ext != NULL) {
-               sprintf(fext,"-f%s",batch_ext);
+       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;
        }
 
@@ -653,6 +729,9 @@ void server_options(char **args,int *argc)
        if (only_existing && am_sender)
                args[ac++] = "--existing";
 
+       if (opt_ignore_existing && am_sender) 
+               args[ac++] = "--ignore-existing";
+
        if (tmpdir) {
                args[ac++] = "--temp-dir";
                args[ac++] = tmpdir;