Fixed a bunch of "warn_unused_result" compiler warnings.
[rsync/rsync.git] / options.c
index 013557f..c561f47 100644 (file)
--- a/options.c
+++ b/options.c
@@ -20,7 +20,7 @@
  */
 
 #include "rsync.h"
-#include "ifuncs.h"
+#include "itypes.h"
 #include <popt.h>
 #include "zlib/zlib.h"
 
@@ -78,15 +78,14 @@ int def_compress_level = Z_DEFAULT_COMPRESSION;
 int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */
 int am_server = 0;
 int am_sender = 0;
-int am_generator = 0;
 int am_starting_up = 1;
 int relative_paths = -1;
 int implied_dirs = 1;
 int numeric_ids = 0;
+int msgs2stderr = 0;
 int allow_8bit_chars = 0;
 int force_delete = 0;
 int io_timeout = 0;
-int allowed_lull = 0;
 int prune_empty_dirs = 0;
 int use_qsort = 0;
 char *files_from = NULL;
@@ -94,7 +93,7 @@ int filesfrom_fd = -1;
 char *filesfrom_host = NULL;
 int eol_nulls = 0;
 int protect_args = 0;
-int human_readable = 0;
+int human_readable = 1;
 int recurse = 0;
 int allow_inc_recurse = 1;
 int xfer_dirs = -1;
@@ -103,6 +102,7 @@ int connect_timeout = 0;
 int keep_partial = 0;
 int safe_symlinks = 0;
 int copy_unsafe_links = 0;
+int munge_symlinks = 0;
 int size_only = 0;
 int daemon_bwlimit = 0;
 int bwlimit = 0;
@@ -121,7 +121,9 @@ int checksum_seed = 0;
 int inplace = 0;
 int delay_updates = 0;
 long block_size = 0; /* "long" because popt can't set an int32. */
+char number_separator;
 char *skip_compress = NULL;
+item_list dparam_list = EMPTY_ITEM_LIST;
 
 /** Network address family. **/
 int default_af_hint
@@ -196,21 +198,21 @@ char *iconv_opt = ICONV_OPTION;
 
 struct chmod_mode_struct *chmod_modes = NULL;
 
-static char *debug_verbosity[] = {
+static const char *debug_verbosity[] = {
        /*0*/ NULL,
        /*1*/ NULL,
-       /*2*/ "bind,cmd,chksum,connect,del,dup,filter,flist",
-       /*3*/ "acl,backup,chksum2,del2,exit,filter2,flist2,fuzzy,genr,own,recv,send,time",
-       /*4*/ "cmd2,chksum3,del3,exit2,flist3,iconv,own2,proto,time2",
-       /*5*/ "chdir,chksum4,flist4,fuzzy2,hlink",
+       /*2*/ "bind,cmd,connect,del,deltasum,dup,filter,flist,iconv",
+       /*3*/ "acl,backup,deltasum2,del2,exit,filter2,flist2,fuzzy,genr,own,recv,send,time",
+       /*4*/ "cmd2,deltasum3,del3,exit2,flist3,iconv2,own2,proto,time2",
+       /*5*/ "chdir,deltasum4,flist4,fuzzy2,hash,hlink",
 };
 
 #define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1)
 
-static char *info_verbosity[1+MAX_VERBOSITY] = {
+static const char *info_verbosity[1+MAX_VERBOSITY] = {
        /*0*/ NULL,
        /*1*/ "copy,del,flist,misc,name,stats,symsafe",
-       /*2*/ "backup,misc2,mount,name2,remove,skip",
+       /*2*/ "backup,mount,name2,remove,skip",
 };
 
 #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */
@@ -230,19 +232,20 @@ short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
 struct output_struct {
        char *name;     /* The name of the info/debug flag. */
        char *help;     /* The description of the info/debug flag. */
-       short flag;     /* The flag's value, for consistency check. */
-       short where;    /* Bits indicating where the flag is used. */
-       short priority; /* See *_PRIORITY defines. */
+       uchar namelen;  /* The length of the name string. */
+       uchar flag;     /* The flag's value, for consistency check. */
+       uchar where;    /* Bits indicating where the flag is used. */
+       uchar priority; /* See *_PRIORITY defines. */
 };
 
-#define INFO_WORD(flag, where, help) { #flag, help, INFO_##flag, where, 0 }
+#define INFO_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, INFO_##flag, where, 0 }
 
 static struct output_struct info_words[COUNT_INFO+1] = {
        INFO_WORD(BACKUP, W_REC, "Mention files backed up"),
        INFO_WORD(COPY, W_REC, "Mention files copied locally on the receiving side"),
        INFO_WORD(DEL, W_REC, "Mention deletions on the receiving side"),
        INFO_WORD(FLIST, W_CLI, "Mention file-list receiving/sending (levels 1-2)"),
-       INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information (levels 1-2)"),
+       INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information"),
        INFO_WORD(MOUNT, W_SND|W_REC, "Mention mounts that were found or skipped"),
        INFO_WORD(NAME, W_SND|W_REC, "Mention 1) updated file/dir names, 2) unchanged names"),
        INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"),
@@ -250,10 +253,10 @@ static struct output_struct info_words[COUNT_INFO+1] = {
        INFO_WORD(SKIP, W_REC, "Mention files that are skipped due to options used"),
        INFO_WORD(STATS, W_CLI|W_SRV, "Mention statistics at end of run (levels 1-3)"),
        INFO_WORD(SYMSAFE, W_SND|W_REC, "Mention symlinks that are unsafe"),
-       { NULL, "--info", 0, 0, 0 }
+       { NULL, "--info", 0, 0, 0, 0 }
 };
 
-#define DEBUG_WORD(flag, where, help) { #flag, help, DEBUG_##flag, where, 0 }
+#define DEBUG_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, DEBUG_##flag, where, 0 }
 
 static struct output_struct debug_words[COUNT_DEBUG+1] = {
        DEBUG_WORD(ACL, W_SND|W_REC, "Debug extra ACL info"),
@@ -261,23 +264,24 @@ static struct output_struct debug_words[COUNT_DEBUG+1] = {
        DEBUG_WORD(BIND, W_CLI, "Debug socket bind actions"),
        DEBUG_WORD(CHDIR, W_CLI|W_SRV, "Debug when the current directory changes"),
        DEBUG_WORD(CONNECT, W_CLI, "Debug connection events"),
-       DEBUG_WORD(CHKSUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"),
        DEBUG_WORD(CMD, W_CLI, "Debug commands+options that are issued (levels 1-2)"),
        DEBUG_WORD(DEL, W_REC, "Debug delete actions (levels 1-3)"),
+       DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"),
        DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"),
        DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-2)"),
        DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-2)"),
        DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"),
        DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"),
        DEBUG_WORD(GENR, W_REC, "Debug generator functions"),
+       DEBUG_WORD(HASH, W_SND|W_REC, "Debug hashtable code"),
        DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions"),
-       DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv (character conversion)"),
+       DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv character conversions (levels 1-2)"),
        DEBUG_WORD(OWN, W_REC, "Debug ownership changes in users & groups (levels 1-2)"),
        DEBUG_WORD(PROTO, W_CLI|W_SRV, "Debug protocol information"),
        DEBUG_WORD(RECV, W_REC, "Debug receiver functions"),
        DEBUG_WORD(SEND, W_SND, "Debug sender functions"),
        DEBUG_WORD(TIME, W_REC, "Debug setting of modified times (levels 1-2)"),
-       { NULL, "--debug", 0, 0, 0 }
+       { NULL, "--debug", 0, 0, 0, 0 }
 };
 
 static int verbose = 0;
@@ -306,7 +310,7 @@ static void output_item_help(struct output_struct *words);
  * the --info or --debug setting, skipping any implied options (by -v, etc.).
  * This is used both when conveying the user's options to the server, and
  * when the help output wants to tell the user what options are implied. */
-static char *make_output_option(struct output_struct *words, short *levels, short where)
+static char *make_output_option(struct output_struct *words, short *levels, uchar where)
 {
        char *str = words == info_words ? "--info=" : "--debug=";
        int j, counts[MAX_OUT_LEVEL+1], pos, skipped = 0, len = 0, max = 0, lev = 0;
@@ -391,7 +395,7 @@ static char *make_output_option(struct output_struct *words, short *levels, shor
 }
 
 static void parse_output_words(struct output_struct *words, short *levels,
-                              const char *str, short priority)
+                              const char *str, uchar priority)
 {
        const char *s;
        int j, len, lev;
@@ -419,7 +423,7 @@ static void parse_output_words(struct output_struct *words, short *levels,
                        len = 0;
                for (j = 0; words[j].name; j++) {
                        if (!len
-                        || (strncasecmp(str, words[j].name, len) == 0 && !words[j].name[len])) {
+                        || (len == words[j].namelen && strncasecmp(str, words[j].name, len) == 0)) {
                                if (priority >= words[j].priority) {
                                        words[j].priority = priority;
                                        levels[j] = lev;
@@ -443,7 +447,7 @@ static void parse_output_words(struct output_struct *words, short *levels,
 static void output_item_help(struct output_struct *words)
 {
        short *levels = words == info_words ? info_levels : debug_levels;
-       char **verbosity = words == info_words ? info_verbosity : debug_verbosity;
+       const char **verbosity = words == info_words ? info_verbosity : debug_verbosity;
        char buf[128], *opt, *fmt = "%-10s %s\n";
        int j;
 
@@ -479,7 +483,7 @@ static void output_item_help(struct output_struct *words)
 }
 
 /* The --verbose option now sets info+debug flags. */
-static void set_output_verbosity(int level, short priority)
+static void set_output_verbosity(int level, uchar priority)
 {
        int j;
 
@@ -561,7 +565,8 @@ static void print_rsync_version(enum logcode f)
        STRUCT_STAT *dumstat;
 
 #if SUBPROTOCOL_VERSION != 0
-       asprintf(&subprotocol, ".PR%d", SUBPROTOCOL_VERSION);
+       if (asprintf(&subprotocol, ".PR%d", SUBPROTOCOL_VERSION) < 0)
+               out_of_memory("print_rsync_version");
 #endif
 #ifdef HAVE_SOCKETPAIR
        got_socketpair = "";
@@ -669,6 +674,7 @@ void usage(enum logcode F)
   rprintf(F," -L, --copy-links            transform symlink into referent file/dir\n");
   rprintf(F,"     --copy-unsafe-links     only \"unsafe\" symlinks are transformed\n");
   rprintf(F,"     --safe-links            ignore symlinks that point outside the source tree\n");
+  rprintf(F,"     --munge-links           munge symlinks to make them safer (but unusable)\n");
   rprintf(F," -k, --copy-dirlinks         transform symlink to a dir into referent dir\n");
   rprintf(F," -K, --keep-dirlinks         treat symlinked dir on receiver as dir\n");
   rprintf(F," -H, --hard-links            preserve hard links\n");
@@ -794,6 +800,7 @@ static struct poptOption long_options[] = {
   {"no-v",             0,  POPT_ARG_VAL,    &verbose, 0, 0, 0 },
   {"info",             0,  POPT_ARG_STRING, 0, OPT_INFO, 0, 0 },
   {"debug",            0,  POPT_ARG_STRING, 0, OPT_DEBUG, 0, 0 },
+  {"msgs2stderr",      0,  POPT_ARG_NONE,   &msgs2stderr, 0, 0, 0 },
   {"quiet",           'q', POPT_ARG_NONE,   0, 'q', 0, 0 },
   {"motd",             0,  POPT_ARG_VAL,    &output_motd, 1, 0, 0 },
   {"no-motd",          0,  POPT_ARG_VAL,    &output_motd, 0, 0, 0 },
@@ -853,6 +860,8 @@ static struct poptOption long_options[] = {
   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links, 0, 0, 0 },
   {"copy-unsafe-links",0,  POPT_ARG_NONE,   &copy_unsafe_links, 0, 0, 0 },
   {"safe-links",       0,  POPT_ARG_NONE,   &safe_symlinks, 0, 0, 0 },
+  {"munge-links",      0,  POPT_ARG_VAL,    &munge_symlinks, 1, 0, 0 },
+  {"no-munge-links",   0,  POPT_ARG_VAL,    &munge_symlinks, 0, 0, 0 },
   {"copy-dirlinks",   'k', POPT_ARG_NONE,   &copy_dirlinks, 0, 0, 0 },
   {"keep-dirlinks",   'K', POPT_ARG_NONE,   &keep_dirlinks, 0, 0, 0 },
   {"hard-links",      'H', POPT_ARG_NONE,   0, 'H', 0, 0 },
@@ -991,6 +1000,7 @@ static struct poptOption long_options[] = {
   /* All the following options switch us into daemon-mode option-parsing. */
   {"config",           0,  POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
   {"daemon",           0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
+  {"dparam",           0,  POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
   {"detach",           0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
   {"no-detach",        0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
   {0,0,0,0, 0, 0, 0}
@@ -1005,6 +1015,7 @@ static void daemon_usage(enum logcode F)
   rprintf(F,"     --address=ADDRESS       bind to the specified address\n");
   rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth; KBytes per second\n");
   rprintf(F,"     --config=FILE           specify alternate rsyncd.conf file\n");
+  rprintf(F," -M, --dparam=OVERRIDE       override global daemon config parameter\n");
   rprintf(F,"     --no-detach             do not detach from the parent\n");
   rprintf(F,"     --port=PORT             listen on alternate port number\n");
   rprintf(F,"     --log-file=FILE         override the \"log file\" setting\n");
@@ -1026,6 +1037,7 @@ static struct poptOption long_daemon_options[] = {
   {"bwlimit",          0,  POPT_ARG_INT,    &daemon_bwlimit, 0, 0, 0 },
   {"config",           0,  POPT_ARG_STRING, &config_file, 0, 0, 0 },
   {"daemon",           0,  POPT_ARG_NONE,   &daemon_opt, 0, 0, 0 },
+  {"dparam",          'M', POPT_ARG_STRING, 0, 'M', 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 },
   {"detach",           0,  POPT_ARG_VAL,    &no_detach, 0, 0, 0 },
@@ -1309,11 +1321,24 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        pc = poptGetContext(RSYNC_NAME, argc, argv,
                                            long_daemon_options, 0);
                        while ((opt = poptGetNextOpt(pc)) != -1) {
+                               char **cpp;
                                switch (opt) {
                                case 'h':
                                        daemon_usage(FINFO);
                                        exit_cleanup(0);
 
+                               case 'M':
+                                       arg = poptGetOptArg(pc);
+                                       if (!strchr(arg, '=')) {
+                                               rprintf(FERROR,
+                                                   "--dparam value is missing an '=': %s\n",
+                                                   arg);
+                                               goto daemon_error;
+                                       }
+                                       cpp = EXPAND_ITEM_LIST(&dparam_list, char *, 4);
+                                       *cpp = strdup(arg);
+                                       break;
+
                                case 'v':
                                        verbose++;
                                        break;
@@ -1327,6 +1352,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                                }
                        }
 
+                       if (dparam_list.count && !set_dparams(1))
+                               exit_cleanup(RERR_SYNTAX);
+
                        if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
                                snprintf(err_buf, sizeof err_buf,
                                         "the --temp-dir path is WAY too long.\n");
@@ -1644,7 +1672,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                }
        }
 
-       if (human_readable && argc == 2 && !am_server) {
+       if (human_readable > 1 && argc == 2 && !am_server) {
                /* Allow the old meaning of 'h' (--help) on its own. */
                usage(FINFO);
                exit_cleanup(0);
@@ -1657,6 +1685,15 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY);
        }
 
+       if (human_readable) {
+               char buf[32];
+               snprintf(buf, sizeof buf, "%f", 3.14);
+               if (strchr(buf, '.') != NULL)
+                       number_separator = ',';
+               else
+                       number_separator = '.';
+       }
+
 #ifdef ICONV_OPTION
        if (iconv_opt && protect_args != 2) {
                if (!am_server && strcmp(iconv_opt, "-") == 0)
@@ -1821,6 +1858,17 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                need_messages_from_generator = 1;
        }
 
+       if (munge_symlinks && !am_daemon) {
+               STRUCT_STAT st;
+               char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */
+               strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */
+               if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) {
+                       rprintf(FERROR, "Symlink munging is unsafe when a %s directory exists.\n",
+                               prefix);
+                       exit_cleanup(RERR_UNSUPPORTED);
+               }
+       }
+
        if (sanitize_paths) {
                int i;
                for (i = argc; i-- > 0; )
@@ -1900,7 +1948,8 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                else if (log_format_has(stdout_format, 'i'))
                        stdout_format_has_i = itemize_changes | 1;
                if (!log_format_has(stdout_format, 'b')
-                && !log_format_has(stdout_format, 'c'))
+                && !log_format_has(stdout_format, 'c')
+                && !log_format_has(stdout_format, 'C'))
                        log_before_transfer = !am_server;
        } else if (itemize_changes) {
                stdout_format = "%i %n%L";
@@ -2082,7 +2131,7 @@ void server_options(char **args, int *argc_p)
 {
        static char argstr[64];
        int ac = *argc_p;
-       short where;
+       uchar where;
        char *arg;
        int i, x;
 
@@ -2207,6 +2256,9 @@ void server_options(char **args, int *argc_p)
                        argstr[x++] = 'i';
 #if defined HAVE_LUTIMES && defined HAVE_UTIMES
                argstr[x++] = 'L';
+#endif
+#ifdef ICONV_OPTION
+               argstr[x++] = 's';
 #endif
        }
 
@@ -2217,7 +2269,8 @@ void server_options(char **args, int *argc_p)
 
        argstr[x] = '\0';
 
-       args[ac++] = argstr;
+       if (x > 1)
+               args[ac++] = argstr;
 
 #ifdef ICONV_OPTION
        if (iconv_opt) {