Added the --info=FLAGS an --debug=FLAGS options, which allows
authorWayne Davison <wayned@samba.org>
Mon, 14 Jul 2008 03:51:08 +0000 (20:51 -0700)
committerWayne Davison <wayned@samba.org>
Mon, 14 Jul 2008 03:51:08 +0000 (20:51 -0700)
fine-grained output control (in addition to the coarse -v).

29 files changed:
NEWS
acls.c
backup.c
batch.c
cleanup.c
clientserver.c
compat.c
exclude.c
flist.c
generator.c
hlink.c
io.c
log.c
main.c
match.c
options.c
pipe.c
progress.c
receiver.c
rsync.c
rsync.h
rsync.yo
sender.c
socket.c
t_unsafe.c
testsuite/00-hello.test
testsuite/rsync.fns
uidlist.c
util.c

diff --git a/NEWS b/NEWS
index 924e788..7be38f2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,11 +7,18 @@ Changes since 3.0.3:
     - Changed the way --progress overwrites its prior output in order to make
       it nearly impossible for the progress to get overwritten by an error.
 
+    - Improved the keep-alive in-loop check in the generator to work properly
+      in incremental recursion mode.
+
   ENHANCEMENTS:
 
     - Added the --remote-option=OPT (-M OPT) command-line option that is useful
       for things like sending a remote --log-file=FILE or --fake-super option.
 
+    - Added the --info=FLAGS and --debug=FLAGS options to allow finer-grained
+      control over what is output.  Added an extra type of --progress output
+      using --info=progress2.
+
     - Rsync will not send an -e option to the server if the user specifies the
       --protocol=29 option.  This lets rsync3 use an overly-restrictive server.
 
diff --git a/acls.c b/acls.c
index d9023e2..3e829ad 100644 (file)
--- a/acls.c
+++ b/acls.c
@@ -1081,7 +1081,7 @@ int default_perms_for_dir(const char *dir)
        /* Apply the permission-bit entries of the default ACL, if any. */
        if (racl.user_obj != NO_ENTRY) {
                perms = rsync_acl_get_perms(&racl);
-               if (verbose > 2)
+               if (DEBUG_GTE(ACL, 1))
                        rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
        }
 
index 934f838..60c85b1 100644 (file)
--- a/backup.c
+++ b/backup.c
@@ -20,7 +20,6 @@
 
 #include "rsync.h"
 
-extern int verbose;
 extern int am_root;
 extern int preserve_acls;
 extern int preserve_xattrs;
@@ -62,7 +61,7 @@ static int make_simple_backup(const char *fname)
 
        while (1) {
                if (do_rename(fname, fnamebak) == 0) {
-                       if (verbose > 1) {
+                       if (INFO_GTE(BACKUP, 1)) {
                                rprintf(FINFO, "backed up %s to %s\n",
                                        fname, fnamebak);
                        }
@@ -260,7 +259,7 @@ static int keep_backup(const char *fname)
                        }
                } else
                        save_errno = 0;
-               if (verbose > 2 && save_errno == 0) {
+               if (DEBUG_GTE(BACKUP, 1) && save_errno == 0) {
                        rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
                                fname);
                }
@@ -285,7 +284,7 @@ static int keep_backup(const char *fname)
                }
 
                ret_code = do_rmdir(fname);
-               if (verbose > 2) {
+               if (DEBUG_GTE(BACKUP, 1)) {
                        rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
                                full_fname(fname), ret_code);
                }
@@ -296,7 +295,7 @@ static int keep_backup(const char *fname)
        if (!kept && preserve_links && S_ISLNK(file->mode)) {
                const char *sl = F_SYMLINK(file);
                if (safe_symlinks && unsafe_symlink(sl, buf)) {
-                       if (verbose) {
+                       if (INFO_GTE(SYMSAFE, 1)) {
                                rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
                                        full_fname(buf), sl);
                        }
@@ -345,7 +344,7 @@ static int keep_backup(const char *fname)
        preserve_xattrs = save_preserve_xattrs;
        unmake_file(file);
 
-       if (verbose > 1) {
+       if (INFO_GTE(BACKUP, 1)) {
                rprintf(FINFO, "backed up %s to %s\n",
                        fname, buf);
        }
diff --git a/batch.c b/batch.c
index 033368a..ac89583 100644 (file)
--- a/batch.c
+++ b/batch.c
@@ -135,7 +135,7 @@ void check_batch_flags(void)
                                        set ? "Please" : "Do not");
                                exit_cleanup(RERR_SYNTAX);
                        }
-                       if (verbose) {
+                       if (INFO_GTE(MISC, 1)) {
                                rprintf(FINFO,
                                        "%sing the %s option to match the batchfile.\n",
                                        set ? "Sett" : "Clear", flag_name[i]);
index 279b532..9146782 100644 (file)
--- a/cleanup.c
+++ b/cleanup.c
@@ -27,7 +27,7 @@ extern int am_daemon;
 extern int io_error;
 extern int keep_partial;
 extern int got_xfer_error;
-extern int progress_is_active;
+extern int output_needs_newline;
 extern char *partial_dir;
 extern char *logfile_name;
 
@@ -116,12 +116,12 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
 
                exit_code = unmodified_code = code;
 
-               if (progress_is_active) {
+               if (output_needs_newline) {
                        fputc('\n', stdout);
-                       progress_is_active = 0;
+                       output_needs_newline = 0;
                }
 
-               if (verbose > 3) {
+               if (DEBUG_GTE(EXIT, 2)) {
                        rprintf(FINFO,
                                "_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
                                code, file, line);
@@ -184,13 +184,13 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
                                code = exit_code = RERR_PARTIAL;
                }
 
-               if (code || am_daemon || (logfile_name && (am_server || !verbose)))
+               if (code || am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1))))
                        log_exit(code, file, line);
 
                /* FALLTHROUGH */
 #include "case_N.h"
 
-               if (verbose > 2) {
+               if (DEBUG_GTE(EXIT, 1)) {
                        rprintf(FINFO,
                                "_exit_cleanup(code=%d, file=%s, line=%d): "
                                "about to call exit(%d)\n",
index f78c61c..2ba7dbd 100644 (file)
@@ -23,7 +23,6 @@
 #include "ifuncs.h"
 
 extern int quiet;
-extern int verbose;
 extern int dry_run;
 extern int output_motd;
 extern int list_only;
@@ -267,7 +266,7 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
 
        sargs[sargc] = NULL;
 
-       if (verbose > 1)
+       if (DEBUG_GTE(CMD, 1))
                print_child_argv("sending daemon args:", sargs);
 
        io_printf(f_out, "%.*s\n", modlen, modname);
@@ -747,7 +746,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
        read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request);
        orig_argv = argv;
 
-       verbose = 0; /* future verbosity is controlled by client options */
+       reset_output_levels(); /* future verbosity is controlled by client options */
        ret = parse_arguments(&argc, (const char ***) &argv);
        if (protect_args && ret) {
                orig_early_argv = orig_argv;
@@ -798,8 +797,7 @@ static int rsync_module(int f_in, int f_out, int i, char *addr, char *host)
 
 #ifndef DEBUG
        /* don't allow the logs to be flooded too fast */
-       if (verbose > lp_max_verbosity(i))
-               verbose = lp_max_verbosity(i);
+       limit_output_verbosity(lp_max_verbosity(i));
 #endif
 
        if (protocol_version < 23
index ef220e2..811f6ec 100644 (file)
--- a/compat.c
+++ b/compat.c
@@ -25,7 +25,6 @@ int remote_protocol = 0;
 int file_extra_cnt = 0; /* count of file-list extras that everyone gets */
 int inc_recurse = 0;
 
-extern int verbose;
 extern int am_server;
 extern int am_sender;
 extern int local_server;
@@ -157,7 +156,7 @@ void setup_protocol(int f_out,int f_in)
                exit_cleanup(RERR_PROTOCOL);
        }
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(PROTO, 1)) {
                rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n",
                        am_server? "Server" : "Client", remote_protocol, protocol_version);
        }
index 085d264..080aa49 100644 (file)
--- a/exclude.c
+++ b/exclude.c
@@ -22,7 +22,6 @@
 
 #include "rsync.h"
 
-extern int verbose;
 extern int am_server;
 extern int am_sender;
 extern int eol_nulls;
@@ -123,7 +122,7 @@ static void add_rule(struct filter_list_struct *listp, const char *pat,
        const char *cp;
        unsigned int pre_len, suf_len, slash_cnt = 0;
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(FILTER, 2)) {
                rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s\n",
                        who_am_i(), get_rule_prefix(mflags, pat, 0, NULL),
                        (int)pat_len, pat,
@@ -455,7 +454,7 @@ void *push_local_filters(const char *dir, unsigned int dirlen)
                struct filter_struct *ex = mergelist_parents[i];
                struct filter_list_struct *lp = ex->u.mergelist;
 
-               if (verbose > 2) {
+               if (DEBUG_GTE(FILTER, 2)) {
                        rprintf(FINFO, "[%s] pushing filter list%s\n",
                                who_am_i(), lp->debug_type);
                }
@@ -495,7 +494,7 @@ void pop_local_filters(void *mem)
                struct filter_struct *ex = mergelist_parents[i];
                struct filter_list_struct *lp = ex->u.mergelist;
 
-               if (verbose > 2) {
+               if (DEBUG_GTE(FILTER, 2)) {
                        rprintf(FINFO, "[%s] popping filter list%s\n",
                                who_am_i(), lp->debug_type);
                }
@@ -629,7 +628,7 @@ static void report_filter_result(enum logcode code, char const *name,
         * then it is stripped out by add_rule().  So as a special
         * case we add it back in here. */
 
-       if (verbose >= 2) {
+       if (DEBUG_GTE(FILTER, 1)) {
                static char *actions[2][2]
                    = { {"show", "hid"}, {"risk", "protect"} };
                const char *w = who_am_i();
@@ -973,7 +972,7 @@ void parse_rule(struct filter_list_struct *listp, const char *pattern,
                }
 
                if (new_mflags & MATCHFLG_CLEAR_LIST) {
-                       if (verbose > 2) {
+                       if (DEBUG_GTE(FILTER, 2)) {
                                rprintf(FINFO,
                                        "[%s] clearing filter list%s\n",
                                        who_am_i(), listp->debug_type);
@@ -1047,7 +1046,7 @@ void parse_filter_file(struct filter_list_struct *listp, const char *fname,
        } else
                fp = stdin;
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(FILTER, 2)) {
                rprintf(FINFO, "[%s] parse_filter_file(%s,%x,%x)%s\n",
                        who_am_i(), fname, mflags, xflags,
                        fp ? "" : " [not found]");
diff --git a/flist.c b/flist.c
index 18b239e..e0cad79 100644 (file)
--- a/flist.c
+++ b/flist.c
 #include "rounding.h"
 #include "io.h"
 
-extern int verbose;
 extern int am_root;
 extern int am_server;
 extern int am_daemon;
 extern int am_sender;
 extern int am_generator;
 extern int inc_recurse;
-extern int do_progress;
 extern int always_checksum;
 extern int module_id;
 extern int ignore_errors;
@@ -67,6 +65,7 @@ extern int protocol_version;
 extern int sanitize_paths;
 extern int munge_symlinks;
 extern int need_unsorted_flist;
+extern int output_needs_newline;
 extern int unsort_ndx;
 extern struct stats stats;
 extern char *filesfrom_host;
@@ -129,7 +128,7 @@ static void output_flist(struct file_list *flist);
 
 void init_flist(void)
 {
-       if (verbose > 4) {
+       if (DEBUG_GTE(FLIST, 4)) {
                rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
                        (int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
        }
@@ -140,14 +139,13 @@ void init_flist(void)
 
 static int show_filelist_p(void)
 {
-       return verbose && xfer_dirs && !am_server && !inc_recurse;
+       return INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
 }
 
 static void start_filelist_progress(char *kind)
 {
        rprintf(FCLIENT, "%s ... ", kind);
-       if (verbose > 1 || do_progress)
-               rprintf(FCLIENT, "\n");
+       output_needs_newline = 1;
        rflush(FINFO);
 }
 
@@ -158,18 +156,20 @@ static void emit_filelist_progress(int count)
 
 static void maybe_emit_filelist_progress(int count)
 {
-       if (do_progress && show_filelist_p() && (count % 100) == 0)
+       if (INFO_GTE(FLIST, 2) && show_filelist_p() && (count % 100) == 0)
                emit_filelist_progress(count);
 }
 
 static void finish_filelist_progress(const struct file_list *flist)
 {
-       if (do_progress) {
+       if (INFO_GTE(FLIST, 2)) {
                /* This overwrites the progress line */
                rprintf(FINFO, "%d file%sto consider\n",
                        flist->used, flist->used == 1 ? " " : "s ");
-       } else
+       } else {
+               output_needs_newline = 0;
                rprintf(FINFO, "done\n");
+       }
 }
 
 void show_flist_stats(void)
@@ -196,7 +196,7 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf)
                        return -1;
                linkbuf[llen] = '\0';
                if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) {
-                       if (verbose > 1) {
+                       if (INFO_GTE(SYMSAFE, 1)) {
                                rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n",
                                        path, linkbuf);
                        }
@@ -316,7 +316,7 @@ static void flist_expand(struct file_list *flist, int extra)
        new_ptr = realloc_array(flist->files, struct file_struct *,
                                flist->malloced);
 
-       if (verbose >= 2 && flist->malloced != FLIST_START) {
+       if (DEBUG_GTE(FLIST, 1) && flist->malloced != FLIST_START) {
                rprintf(FCLIENT, "[%s] expand file_list pointer array to %.0f bytes, did%s move\n",
                    who_am_i(),
                    (double)sizeof flist->files[0] * flist->malloced,
@@ -1110,7 +1110,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
                if (one_file_system && st.st_dev != filesystem_dev
                 && BITS_SETnUNSET(flags, FLAG_CONTENT_DIR, FLAG_TOP_DIR)) {
                        if (one_file_system > 1) {
-                               if (verbose > 1) {
+                               if (INFO_GTE(MOUNT, 1)) {
                                        rprintf(FINFO,
                                            "[%s] skipping mount-point dir %s\n",
                                            who_am_i(), thisname);
@@ -1159,7 +1159,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
                pool = NULL;
        }
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(FLIST, 2)) {
                rprintf(FINFO, "[%s] make_file(%s,*,%d)\n",
                        who_am_i(), thisname, filter_level);
        }
@@ -1829,7 +1829,7 @@ void send_extra_file_list(int f, int at_least)
                file_total += flist->used;
                stats.flist_size += stats.total_written - start_write;
                stats.num_files += flist->used;
-               if (verbose > 3)
+               if (DEBUG_GTE(FLIST, 3))
                        output_flist(flist);
 
                if (DIR_FIRST_CHILD(dp) >= 0) {
@@ -1880,7 +1880,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        rprintf(FLOG, "building file list\n");
        if (show_filelist_p())
                start_filelist_progress("building file list");
-       else if (inc_recurse && verbose && !am_server)
+       else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
                rprintf(FCLIENT, "sending incremental file list\n");
 
        start_write = stats.total_written;
@@ -2155,10 +2155,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        stats.flist_size = stats.total_written - start_write;
        stats.num_files = flist->used;
 
-       if (verbose > 3)
+       if (DEBUG_GTE(FLIST, 3))
                output_flist(flist);
 
-       if (verbose > 2)
+       if (DEBUG_GTE(FLIST, 2))
                rprintf(FINFO, "send_file_list done\n");
 
        if (inc_recurse) {
@@ -2192,7 +2192,7 @@ struct file_list *recv_file_list(int f)
                rprintf(FLOG, "receiving file list\n");
        if (show_filelist_p())
                start_filelist_progress("receiving file list");
-       else if (inc_recurse && verbose && !am_server && !first_flist)
+       else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server && !first_flist)
                rprintf(FCLIENT, "receiving incremental file list\n");
 
        start_read = stats.total_read;
@@ -2231,14 +2231,14 @@ struct file_list *recv_file_list(int f)
 
                maybe_emit_filelist_progress(flist->used);
 
-               if (verbose > 2) {
+               if (DEBUG_GTE(FLIST, 2)) {
                        rprintf(FINFO, "recv_file_name(%s)\n",
                                f_name(file, NULL));
                }
        }
        file_total += flist->used;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(FLIST, 2))
                rprintf(FINFO, "received %d names\n", flist->used);
 
        if (show_filelist_p())
@@ -2292,10 +2292,10 @@ struct file_list *recv_file_list(int f)
                        flist->parent_ndx = -1;
        }
 
-       if (verbose > 3)
+       if (DEBUG_GTE(FLIST, 3))
                output_flist(flist);
 
-       if (verbose > 2)
+       if (DEBUG_GTE(FLIST, 2))
                rprintf(FINFO, "recv_file_list done\n");
 
        stats.flist_size += stats.total_read - start_read;
@@ -2323,7 +2323,7 @@ void recv_additional_file_list(int f)
                                NDX_FLIST_OFFSET - dir_flist->used + 1);
                        exit_cleanup(RERR_PROTOCOL);
                }
-               if (verbose > 3) {
+               if (DEBUG_GTE(FLIST, 3)) {
                        rprintf(FINFO, "[%s] receiving flist for dir %d\n",
                                who_am_i(), ndx);
                }
@@ -2545,7 +2545,7 @@ static void flist_sort_and_clean(struct file_list *flist, int strip_root)
                                keep = j, drop = i;
 
                        if (!am_sender) {
-                               if (verbose > 1) {
+                               if (DEBUG_GTE(DUP, 1)) {
                                        rprintf(FINFO,
                                            "removing duplicate name %s from file list (%d)\n",
                                            f_name(file, fbuf), drop + flist->ndx_start);
@@ -2903,7 +2903,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules)
        send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, 0);
        xfer_dirs = save_xfer_dirs;
        recurse = save_recurse;
-       if (do_progress)
+       if (INFO_GTE(PROGRESS, 1))
                flist_count_offset += dirlist->used;
 
        prune_empty_dirs = 0;
@@ -2911,7 +2911,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules)
        flist_sort_and_clean(dirlist, 0);
        prune_empty_dirs = save_prune_empty_dirs;
 
-       if (verbose > 3)
+       if (DEBUG_GTE(FLIST, 3))
                output_flist(dirlist);
 
        return dirlist;
index 11cba3c..22f2851 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "rsync.h"
 
-extern int verbose;
 extern int dry_run;
 extern int do_xfers;
 extern int stdout_format_has_i;
@@ -31,7 +30,6 @@ extern int am_root;
 extern int am_server;
 extern int am_daemon;
 extern int inc_recurse;
-extern int do_progress;
 extern int relative_paths;
 extern int implied_dirs;
 extern int keep_dirlinks;
@@ -160,7 +158,7 @@ static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags)
        char *what;
        int ok;
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(DEL, 2)) {
                rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
                        fbuf, (int)mode, (int)flags);
        }
@@ -251,7 +249,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
        int j, dlen;
        char *p;
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(DEL, 3)) {
                rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
                        fname, flags);
        }
@@ -284,7 +282,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags)
                struct file_struct *fp = dirlist->files[j];
 
                if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
-                       if (verbose > 1) {
+                       if (DEBUG_GTE(DEL, 1)) {
                                rprintf(FINFO,
                                    "mount point, %s, pins parent directory\n",
                                    f_name(fp, NULL));
@@ -479,7 +477,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                return;
        }
 
-       if (verbose > 2)
+       if (DEBUG_GTE(DEL, 2))
                rprintf(FINFO, "delete_in_dir(%s)\n", fbuf);
 
        if (allowed_lull)
@@ -516,7 +514,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                if (!F_IS_ACTIVE(fp))
                        continue;
                if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
-                       if (verbose > 1)
+                       if (INFO_GTE(MOUNT, 1))
                                rprintf(FINFO, "cannot delete mount point: %s\n",
                                        f_name(fp, NULL));
                        continue;
@@ -564,7 +562,7 @@ static void do_delete_pass(void)
                        continue;
                }
 
-               if (verbose > 1 && file->flags & FLAG_TOP_DIR)
+               if (DEBUG_GTE(DEL, 1) && file->flags & FLAG_TOP_DIR)
                        rprintf(FINFO, "deleting in %s\n", fbuf);
 
                if (link_stat(fbuf, &st, keep_dirlinks) < 0
@@ -575,7 +573,7 @@ static void do_delete_pass(void)
        }
        delete_in_dir(NULL, NULL, &dev_zero);
 
-       if (do_progress && !am_server)
+       if (INFO_GTE(FLIST, 2) && !am_server)
                rprintf(FINFO, "                    \r");
 }
 
@@ -686,7 +684,7 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
        }
 
        iflags &= 0xffff;
-       if ((iflags & (SIGNIFICANT_ITEM_FLAGS|ITEM_REPORT_XATTR) || verbose > 1
+       if ((iflags & (SIGNIFICANT_ITEM_FLAGS|ITEM_REPORT_XATTR) || INFO_GTE(NAME, 2)
          || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) {
                if (protocol_version >= 29) {
                        if (ndx >= 0)
@@ -805,7 +803,7 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
        if ((int64)sum->count != l)
                sum->count = -1;
 
-       if (sum->count && verbose > 2) {
+       if (sum->count && DEBUG_GTE(CHKSUM, 2)) {
                rprintf(FINFO,
                        "count=%.0f rem=%ld blength=%ld s2length=%d flength=%.0f\n",
                        (double)sum->count, (long)sum->remainder, (long)sum->blength,
@@ -857,7 +855,7 @@ static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
                sum1 = get_checksum1(map, n1);
                get_checksum2(map, n1, sum2);
 
-               if (verbose > 3) {
+               if (DEBUG_GTE(CHKSUM, 3)) {
                        rprintf(FINFO,
                                "chunk[%.0f] offset=%.0f len=%ld sum1=%08lx\n",
                                (double)i, (double)offset - n1, (long)n1,
@@ -899,7 +897,7 @@ static int find_fuzzy(struct file_struct *file, struct file_list *dirlist)
 
                if (F_LENGTH(fp) == F_LENGTH(file)
                    && cmp_time(fp->modtime, file->modtime) == 0) {
-                       if (verbose > 4) {
+                       if (DEBUG_GTE(FUZZY, 2)) {
                                rprintf(FINFO,
                                        "fuzzy size/modtime match for %s\n",
                                        name);
@@ -914,7 +912,7 @@ static int find_fuzzy(struct file_struct *file, struct file_list *dirlist)
                /* Add some extra weight to how well the suffixes match. */
                dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len)
                      * 10;
-               if (verbose > 4) {
+               if (DEBUG_GTE(FUZZY, 2)) {
                        rprintf(FINFO, "fuzzy distance for %s = %d.%05d\n",
                                name, (int)(dist>>16), (int)(dist&0xFFFF));
                }
@@ -947,7 +945,7 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
        }
        cleanup_set(copy_to, NULL, NULL, -1, -1);
        if (copy_file(src, copy_to, fd_w, file->mode, 0) < 0) {
-               if (verbose) {
+               if (INFO_GTE(COPY, 1)) {
                        rsyserr(FINFO, errno, "copy_file %s => %s",
                                full_fname(src), copy_to);
                }
@@ -1017,7 +1015,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
                                goto try_a_copy;
                        if (preserve_hard_links && F_IS_HLINKED(file))
                                finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j);
-                       if (!maybe_ATTRS_REPORT && (verbose > 1 || stdout_format_has_i > 1)) {
+                       if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
                                itemize(cmpbuf, file, ndx, 1, sxp,
                                        ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
                                        0, "");
@@ -1026,7 +1024,7 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
 #endif
                if (itemizing)
                        itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL);
-               if (verbose > 1 && maybe_ATTRS_REPORT)
+               if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
                        rprintf(FCLIENT, "%s is uptodate\n", fname);
                return -2;
        }
@@ -1040,8 +1038,8 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
                if (itemizing)
                        itemize(cmpbuf, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
                if (maybe_ATTRS_REPORT
-                && ((!itemizing && verbose && match_level == 2)
-                 || (verbose > 1 && match_level == 3))) {
+                && ((!itemizing && INFO_GTE(NAME, 1) && match_level == 2)
+                 || (INFO_GTE(NAME, 2) && match_level == 3))) {
                        code = match_level == 3 ? FCLIENT : FINFO;
                        rprintf(code, "%s%s\n", fname,
                                match_level == 3 ? " is uptodate" : "");
@@ -1181,13 +1179,13 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
 #endif
                        match_level = 2;
                if (itemizing && stdout_format_has_i
-                && (verbose > 1 || stdout_format_has_i > 1)) {
+                && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
                        int chg = compare_dest && type != TYPE_DIR ? 0
                            : ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
                        char *lp = match_level == 3 ? "" : NULL;
                        itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
                }
-               if (verbose > 1 && maybe_ATTRS_REPORT) {
+               if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) {
                        rprintf(FCLIENT, "%s%s is uptodate\n",
                                fname, type == TYPE_DIR ? "/" : "");
                }
@@ -1273,7 +1271,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                   : inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1
                   : 1;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(GENR, 1))
                rprintf(FINFO, "recv_generator(%s,%d)\n", fname, ndx);
 
        if (list_only) {
@@ -1377,7 +1375,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                else if (F_IS_HLINKED(file))
                        handle_skipped_hlink(file, itemizing, code, f_out);
 #endif
-               if (verbose > 1) {
+               if (INFO_GTE(SKIP, 1)) {
                        rprintf(FINFO, "not creating new %s \"%s\"\n",
                                is_dir ? "directory" : "file", fname);
                }
@@ -1390,7 +1388,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
        if (ignore_existing > 0 && statret == 0
         && (!is_dir || !S_ISDIR(sx.st.st_mode))) {
-               if (verbose > 1 && is_dir >= 0)
+               if (INFO_GTE(SKIP, 1) && is_dir >= 0)
                        rprintf(FINFO, "%s exists\n", fname);
 #ifdef SUPPORT_HARD_LINKS
                if (F_IS_HLINKED(file))
@@ -1473,7 +1471,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        copy_xattrs(fnamecmpbuf, fname);
 #endif
                if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
-                   && verbose && code != FNONE && f_out != -1)
+                   && INFO_GTE(NAME, 1) && code != FNONE && f_out != -1)
                        rprintf(code, "%s/\n", fname);
 
                /* We need to ensure that the dirs in the transfer have writable
@@ -1528,7 +1526,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 #ifdef SUPPORT_LINKS
                const char *sl = F_SYMLINK(file);
                if (safe_symlinks && unsafe_symlink(sl, fname)) {
-                       if (verbose) {
+                       if (INFO_GTE(NAME, 1)) {
                                if (solo_file)
                                        fname = f_name(file, NULL);
                                rprintf(FINFO,
@@ -1592,7 +1590,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                itemize(fname, file, ndx, statret, &sx,
                                        ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
                        }
-                       if (code != FNONE && verbose)
+                       if (code != FNONE && INFO_GTE(NAME, 1))
                                rprintf(code, "%s -> %s\n", fname, sl);
 #ifdef SUPPORT_HARD_LINKS
                        if (preserve_hard_links && F_IS_HLINKED(file))
@@ -1662,7 +1660,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        goto cleanup;
                }
 #endif
-               if (verbose > 2) {
+               if (DEBUG_GTE(GENR, 1)) {
                        rprintf(FINFO, "mknod(%s, 0%o, [%ld,%ld])\n",
                                fname, (int)file->mode,
                                (long)major(rdev), (long)minor(rdev));
@@ -1676,7 +1674,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                itemize(fname, file, ndx, statret, &sx,
                                        ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL);
                        }
-                       if (code != FNONE && verbose)
+                       if (code != FNONE && INFO_GTE(NAME, 1))
                                rprintf(code, "%s\n", fname);
 #ifdef SUPPORT_HARD_LINKS
                        if (preserve_hard_links && F_IS_HLINKED(file))
@@ -1696,7 +1694,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
        }
 
        if (max_size > 0 && F_LENGTH(file) > max_size) {
-               if (verbose > 1) {
+               if (INFO_GTE(SKIP, 1)) {
                        if (solo_file)
                                fname = f_name(file, NULL);
                        rprintf(FINFO, "%s is over max-size\n", fname);
@@ -1704,7 +1702,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                goto cleanup;
        }
        if (min_size > 0 && F_LENGTH(file) < min_size) {
-               if (verbose > 1) {
+               if (INFO_GTE(SKIP, 1)) {
                        if (solo_file)
                                fname = f_name(file, NULL);
                        rprintf(FINFO, "%s is under min-size\n", fname);
@@ -1714,7 +1712,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
        if (update_only > 0 && statret == 0
            && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
-               if (verbose > 1)
+               if (INFO_GTE(SKIP, 1))
                        rprintf(FINFO, "%s is newer\n", fname);
 #ifdef SUPPORT_HARD_LINKS
                if (F_IS_HLINKED(file))
@@ -1764,7 +1762,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                if (j >= 0) {
                        fuzzy_file = fuzzy_dirlist->files[j];
                        f_name(fuzzy_file, fnamecmpbuf);
-                       if (verbose > 2) {
+                       if (DEBUG_GTE(FUZZY, 1)) {
                                rprintf(FINFO, "fuzzy basis selected for %s: %s\n",
                                        fname, fnamecmpbuf);
                        }
@@ -1905,12 +1903,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                fnamecmp_type = FNAMECMP_BACKUP;
        }
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(CHKSUM, 3)) {
                rprintf(FINFO, "gen mapped %s of size %.0f\n",
                        fnamecmp, (double)sx.st.st_size);
        }
 
-       if (verbose > 2)
+       if (DEBUG_GTE(CHKSUM, 2))
                rprintf(FINFO, "generating and sending sums for %d\n", ndx);
 
   notify_others:
@@ -1981,7 +1979,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 #endif
                set_file_attrs(backupptr, back_file, NULL, NULL, 0);
                preserve_xattrs = save_preserve_xattrs;
-               if (verbose > 1) {
+               if (INFO_GTE(BACKUP, 1)) {
                        rprintf(FINFO, "backed up %s to %s\n",
                                fname, backupptr);
                }
@@ -2041,7 +2039,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
                if (!S_ISDIR(file->mode)
                 || (!implied_dirs && file->flags & FLAG_IMPLIED_DIR))
                        continue;
-               if (verbose > 3) {
+               if (DEBUG_GTE(TIME, 2)) {
                        fname = f_name(file, NULL);
                        rprintf(FINFO, "touch_up_dirs: %s (%d)\n",
                                NS(fname), i);
@@ -2155,7 +2153,8 @@ void generate_files(int f_out, const char *local_name)
        char fbuf[MAXPATHLEN];
        int itemizing;
        enum logcode code;
-       int save_do_progress = do_progress;
+       int save_info_flist = info_levels[INFO_FLIST];
+       int save_info_progress = info_levels[INFO_PROGRESS];
 
        if (protocol_version >= 29) {
                itemizing = 1;
@@ -2182,7 +2181,7 @@ void generate_files(int f_out, const char *local_name)
            | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
        implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(GENR, 1))
                rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid());
 
        if (delete_before && !solo_file && cur_flist->used > 0)
@@ -2193,11 +2192,11 @@ void generate_files(int f_out, const char *local_name)
                if (!deldelay_buf)
                        out_of_memory("delete-delay");
        }
-       do_progress = 0;
+       info_levels[INFO_FLIST] = info_levels[INFO_PROGRESS] = 0;
 
        if (append_mode > 0 || whole_file < 0)
                whole_file = 0;
-       if (verbose >= 2) {
+       if (DEBUG_GTE(FLIST, 1)) {
                rprintf(FINFO, "delta-transmission %s\n",
                        whole_file
                        ? "disabled for local transfer or --whole-file"
@@ -2286,7 +2285,7 @@ void generate_files(int f_out, const char *local_name)
        if (delete_during)
                delete_in_dir(NULL, NULL, &dev_zero);
        phase++;
-       if (verbose > 2)
+       if (DEBUG_GTE(GENR, 1))
                rprintf(FINFO, "generate_files phase=%d\n", phase);
 
        while (1) {
@@ -2297,7 +2296,7 @@ void generate_files(int f_out, const char *local_name)
        }
 
        phase++;
-       if (verbose > 2)
+       if (DEBUG_GTE(GENR, 1))
                rprintf(FINFO, "generate_files phase=%d\n", phase);
 
        write_ndx(f_out, NDX_DONE);
@@ -2315,7 +2314,7 @@ void generate_files(int f_out, const char *local_name)
 
        if (protocol_version >= 29) {
                phase++;
-               if (verbose > 2)
+               if (DEBUG_GTE(GENR, 1))
                        rprintf(FINFO, "generate_files phase=%d\n", phase);
                if (delay_updates)
                        write_ndx(f_out, NDX_DONE);
@@ -2324,7 +2323,9 @@ void generate_files(int f_out, const char *local_name)
                        wait_for_receiver();
        }
 
-       do_progress = save_do_progress;
+       info_levels[INFO_FLIST] = save_info_flist;
+       info_levels[INFO_PROGRESS] = save_info_progress;
+
        if (delete_during == 2)
                do_delayed_deletions(fbuf);
        if (delete_after && !solo_file && file_total > 0)
@@ -2341,6 +2342,6 @@ void generate_files(int f_out, const char *local_name)
                io_error |= IOERR_DEL_LIMIT;
        }
 
-       if (verbose > 2)
+       if (DEBUG_GTE(GENR, 1))
                rprintf(FINFO, "generate_files finished\n");
 }
diff --git a/hlink.c b/hlink.c
index 1e8adc8..d6d0ecf 100644 (file)
--- a/hlink.c
+++ b/hlink.c
@@ -22,7 +22,6 @@
 
 #include "rsync.h"
 
-extern int verbose;
 extern int dry_run;
 extern int list_only;
 extern int am_sender;
@@ -215,7 +214,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
                                        ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
                                        0, "");
                        }
-                       if (verbose > 1 && maybe_ATTRS_REPORT)
+                       if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
                                rprintf(FCLIENT, "%s is uptodate\n", fname);
                        file->flags |= FLAG_HLINK_DONE;
                        return 0;
@@ -236,7 +235,7 @@ static int maybe_hard_link(struct file_struct *file, int ndx,
                                ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
                                realname);
                }
-               if (code != FNONE && verbose)
+               if (code != FNONE && INFO_GTE(NAME, 1))
                        rprintf(code, "%s => %s\n", fname, realname);
                return 0;
        }
@@ -377,10 +376,10 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
                                        continue;
                                statret = 1;
                                if (stdout_format_has_i == 0
-                                || (verbose < 2 && stdout_format_has_i < 2)) {
+                                || (!INFO_GTE(NAME, 2) && stdout_format_has_i < 2)) {
                                        itemizing = 0;
                                        code = FNONE;
-                                       if (verbose > 1 && maybe_ATTRS_REPORT)
+                                       if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT)
                                                rprintf(FCLIENT, "%s is uptodate\n", fname);
                                }
                                break;
@@ -426,7 +425,7 @@ int hard_link_one(struct file_struct *file, const char *fname,
        if (do_link(oldname, fname) < 0) {
                enum logcode code;
                if (terse) {
-                       if (!verbose)
+                       if (!INFO_GTE(NAME, 1))
                                return 0;
                        code = FINFO;
                } else
diff --git a/io.c b/io.c
index 6a91ffd..b21dff4 100644 (file)
--- a/io.c
+++ b/io.c
@@ -408,7 +408,7 @@ static void read_msg_fd(void)
                /* Read extra file list from receiver. */
                assert(iobuf_in != NULL);
                assert(iobuf_f_in == fd);
-               if (verbose > 3) {
+               if (DEBUG_GTE(FLIST, 2)) {
                        rprintf(FINFO, "[%s] receiving flist for dir %d\n",
                                who_am_i(), IVAL(buf,0));
                }
diff --git a/log.c b/log.c
index 9100f5d..4a4c404 100644 (file)
--- a/log.c
+++ b/log.c
@@ -22,7 +22,6 @@
 #include "rsync.h"
 #include "ifuncs.h"
 
-extern int verbose;
 extern int dry_run;
 extern int am_daemon;
 extern int am_server;
@@ -37,7 +36,6 @@ extern int protocol_version;
 extern int preserve_times;
 extern int uid_ndx;
 extern int gid_ndx;
-extern int progress_is_active;
 extern int stdout_format_has_i;
 extern int stdout_format_has_o_or_i;
 extern int logfile_format_has_i;
@@ -64,6 +62,7 @@ static FILE *logfile_fp;
 struct stats stats;
 
 int got_xfer_error = 0;
+int output_needs_newline = 0;
 
 struct {
         int code;
@@ -321,9 +320,9 @@ void rwrite(enum logcode code, const char *buf, int len, int is_utf8)
                exit_cleanup(RERR_MESSAGEIO);
        }
 
-       if (progress_is_active) {
+       if (output_needs_newline) {
                fputc('\n', f);
-               progress_is_active = 0;
+               output_needs_newline = 0;
        }
 
        trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r')
@@ -445,7 +444,7 @@ void rflush(enum logcode code)
        if (am_daemon || code == FLOG)
                return;
 
-       if (code == FINFO && !am_server)
+       if (!am_server && (code == FINFO || code == FCLIENT))
                f = stdout;
        else
                f = stderr;
@@ -767,7 +766,7 @@ void maybe_log_item(struct file_struct *file, int iflags, int itemizing,
 {
        int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS;
        int see_item = itemizing && (significant_flags || *buf
-               || stdout_format_has_i > 1 || (verbose > 1 && stdout_format_has_i));
+               || stdout_format_has_i > 1 || (INFO_GTE(NAME, 2) && stdout_format_has_i));
        int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags;
        if (am_server) {
                if (logfile_name && !dry_run && see_item
@@ -791,7 +790,7 @@ void log_delete(const char *fname, int mode)
 
        x.file.mode = mode;
 
-       if (!verbose && !stdout_format)
+       if (!INFO_GTE(DEL, 1) && !stdout_format)
                ;
        else if (am_server && protocol_version >= 29 && len < MAXPATHLEN) {
                if (S_ISDIR(mode))
diff --git a/main.c b/main.c
index 6881c8e..5ca8210 100644 (file)
--- a/main.c
+++ b/main.c
@@ -27,7 +27,6 @@
 #include <locale.h>
 #endif
 
-extern int verbose;
 extern int dry_run;
 extern int list_only;
 extern int am_root;
@@ -38,9 +37,9 @@ extern int am_daemon;
 extern int inc_recurse;
 extern int blocking_io;
 extern int remove_source_files;
+extern int output_needs_newline;
 extern int need_messages_from_generator;
 extern int kluge_around_eof;
-extern int do_stats;
 extern int got_xfer_error;
 extern int module_id;
 extern int copy_links;
@@ -183,7 +182,7 @@ static void handle_stats(int f)
        total_read = stats.total_read;
        total_written = stats.total_written;
 
-       if (do_stats && verbose > 1) {
+       if (INFO_GTE(STATS, 3)) {
                /* These come out from every process */
                show_malloc_stats();
                show_flist_stats();
@@ -239,7 +238,7 @@ static void handle_stats(int f)
 
 static void output_summary(void)
 {
-       if (do_stats) {
+       if (INFO_GTE(STATS, 2)) {
                rprintf(FCLIENT, "\n");
                rprintf(FINFO,"Number of files: %d\n", stats.num_files);
                rprintf(FINFO,"Number of files transferred: %d\n",
@@ -268,7 +267,7 @@ static void output_summary(void)
                        human_num(total_read));
        }
 
-       if (verbose || do_stats) {
+       if (INFO_GTE(STATS, 1)) {
                rprintf(FCLIENT, "\n");
                rprintf(FINFO,
                        "sent %s bytes  received %s bytes  %s bytes/sec\n",
@@ -434,7 +433,7 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in
 
        args[argc] = NULL;
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(CMD, 2)) {
                for (i = 0; i < argc; i++)
                        rprintf(FCLIENT, "cmd[%d]=%s ", i, args[i]);
                rprintf(FCLIENT, "\n");
@@ -499,7 +498,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
        int statret;
        char *cp;
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(RECV, 1)) {
                rprintf(FINFO, "get_local_name count=%d %s\n",
                        file_total, NS(dest_path));
        }
@@ -580,7 +579,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path)
                 && strcmp(flist->files[flist->low]->basename, ".") == 0)
                        flist->files[0]->flags |= FLAG_DIR_CREATED;
 
-               if (verbose)
+               if (INFO_GTE(NAME, 1))
                        rprintf(FINFO, "created directory %s\n", dest_path);
 
                if (dry_run) {
@@ -682,7 +681,7 @@ static void do_server_sender(int f_in, int f_out, int argc, char *argv[])
        struct file_list *flist;
        char *dir = argv[0];
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(SEND, 1)) {
                rprintf(FINFO, "server_sender starting pid=%ld\n",
                        (long)getpid());
        }
@@ -775,6 +774,11 @@ static int do_recv(int f_in, int f_out, char *local_name)
                io_flush(FULL_FLUSH);
                handle_stats(f_in);
 
+               if (output_needs_newline) {
+                       fputc('\n', stdout);
+                       output_needs_newline = 0;
+               }
+
                send_msg(MSG_DONE, "", 1, 0);
                write_varlong(error_pipe[1], stats.total_read, 3);
                io_flush(FULL_FLUSH);
@@ -848,15 +852,17 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
        int exit_code;
        struct file_list *flist;
        char *local_name = NULL;
-       int save_verbose = verbose;
+       int negated_levels;
 
        if (filesfrom_fd >= 0) {
                /* We can't mix messages with files-from data on the socket,
-                * so temporarily turn off verbose messages. */
-               verbose = 0;
-       }
+                * so temporarily turn off info/debug messages. */
+               negate_output_levels();
+               negated_levels = 1;
+       } else
+               negated_levels = 0;
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(RECV, 1)) {
                rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
                        argc, (long)getpid());
        }
@@ -901,7 +907,9 @@ static void do_server_recv(int f_in, int f_out, int argc, char *argv[])
        }
        if (inc_recurse && file_total == 1)
                recv_additional_file_list(f_in);
-       verbose = save_verbose;
+
+       if (negated_levels)
+               negate_output_levels();
 
        if (argc > 0)
                local_name = get_local_name(flist,argv[0]);
@@ -1017,7 +1025,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
                        start_write_batch(f_out);
                flist = send_file_list(f_out, argc, argv);
                set_msg_fd_in(-1);
-               if (verbose > 3)
+               if (DEBUG_GTE(FLIST, 3))
                        rprintf(FINFO,"file list sent\n");
 
                if (protocol_version >= 23)
@@ -1030,7 +1038,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
                if (protocol_version >= 24)
                        read_final_goodbye(f_in);
                if (pid != -1) {
-                       if (verbose > 3)
+                       if (DEBUG_GTE(EXIT, 2))
                                rprintf(FINFO,"client_run waiting on %d\n", (int) pid);
                        io_flush(FULL_FLUSH);
                        wait_process_with_flush(pid, &exit_code);
@@ -1072,7 +1080,7 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
        }
 
        if (pid != -1) {
-               if (verbose > 3)
+               if (DEBUG_GTE(RECV, 1))
                        rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid);
                io_flush(FULL_FLUSH);
                wait_process_with_flush(pid, &exit_code);
@@ -1254,7 +1262,7 @@ static int start_client(int argc, char *argv[])
                }
        }
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(CMD, 2)) {
                rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
                        NS(shell_cmd), NS(shell_machine), NS(shell_user),
                        remote_argv ? NS(remote_argv[0]) : "");
diff --git a/match.c b/match.c
index 280e09f..bb40ebf 100644 (file)
--- a/match.c
+++ b/match.c
@@ -21,8 +21,6 @@
 
 #include "rsync.h"
 
-extern int verbose;
-extern int do_progress;
 extern int checksum_seed;
 extern int append_mode;
 
@@ -108,7 +106,7 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf,
        int32 n = (int32)(offset - last_match); /* max value: block_size (int32) */
        int32 j;
 
-       if (verbose > 2 && i >= 0) {
+       if (DEBUG_GTE(CHKSUM, 2) && i >= 0) {
                rprintf(FINFO,
                        "match at %.0f last_match=%.0f j=%d len=%ld n=%ld\n",
                        (double)offset, (double)last_match, i,
@@ -133,7 +131,7 @@ static void matched(int f, struct sum_struct *s, struct map_struct *buf,
        else
                last_match = offset;
 
-       if (buf && do_progress)
+       if (buf && INFO_GTE(PROGRESS, 1))
                show_progress(last_match, buf->file_size);
 }
 
@@ -152,7 +150,7 @@ static void hash_search(int f,struct sum_struct *s,
         * coding of the output to work more efficiently. */
        want_i = 0;
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(CHKSUM, 2)) {
                rprintf(FINFO, "hash search b=%ld len=%.0f\n",
                        (long)s->blength, (double)len);
        }
@@ -164,14 +162,14 @@ static void hash_search(int f,struct sum_struct *s,
        sum = get_checksum1((char *)map, k);
        s1 = sum & 0xFFFF;
        s2 = sum >> 16;
-       if (verbose > 3)
+       if (DEBUG_GTE(CHKSUM, 3))
                rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k);
 
        offset = 0;
 
        end = len + 1 - s->sums[s->count-1].len;
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(CHKSUM, 3)) {
                rprintf(FINFO, "hash search s->blength=%ld len=%.0f count=%.0f\n",
                        (long)s->blength, (double)len, (double)s->count);
        }
@@ -180,7 +178,7 @@ static void hash_search(int f,struct sum_struct *s,
                int done_csum2 = 0;
                int32 i;
 
-               if (verbose > 4) {
+               if (DEBUG_GTE(CHKSUM, 4)) {
                        rprintf(FINFO, "offset=%.0f sum=%04x%04x\n",
                                (double)offset, s2 & 0xFFFF, s1 & 0xFFFF);
                }
@@ -213,7 +211,7 @@ static void hash_search(int f,struct sum_struct *s,
                            && !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
                                continue;
 
-                       if (verbose > 3) {
+                       if (DEBUG_GTE(CHKSUM, 3)) {
                                rprintf(FINFO,
                                        "potential match at %.0f i=%ld sum=%08x\n",
                                        (double)offset, (long)i, sum);
@@ -344,7 +342,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
                if (append_mode == 2) {
                        OFF_T j = 0;
                        for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
-                               if (buf && do_progress)
+                               if (buf && INFO_GTE(PROGRESS, 1))
                                        show_progress(last_match, buf->file_size);
                                sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
                                           CHUNK_SIZE);
@@ -352,7 +350,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
                        }
                        if (last_match < s->flength) {
                                int32 n = (int32)(s->flength - last_match);
-                               if (buf && do_progress)
+                               if (buf && INFO_GTE(PROGRESS, 1))
                                        show_progress(last_match, buf->file_size);
                                sum_update(map_ptr(buf, last_match, n), n);
                        }
@@ -364,12 +362,12 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
        if (len > 0 && s->count > 0) {
                build_hash_table(s);
 
-               if (verbose > 2)
+               if (DEBUG_GTE(CHKSUM, 2))
                        rprintf(FINFO,"built hash table\n");
 
                hash_search(f, s, buf, len);
 
-               if (verbose > 2)
+               if (DEBUG_GTE(CHKSUM, 2))
                        rprintf(FINFO,"done hash search\n");
        } else {
                OFF_T j;
@@ -384,11 +382,11 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
        if (buf && buf->status != 0)
                file_sum[0]++;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(CHKSUM, 2))
                rprintf(FINFO,"sending file_sum\n");
        write_buf(f, file_sum, sum_len);
 
-       if (verbose > 2)
+       if (DEBUG_GTE(CHKSUM, 2))
                rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
                        false_alarms, hash_hits, matches);
 
@@ -400,7 +398,7 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
 
 void match_report(void)
 {
-       if (verbose <= 1)
+       if (!DEBUG_GTE(CHKSUM, 1))
                return;
 
        rprintf(FINFO,
index d534cec..1bdea18 100644 (file)
--- a/options.c
+++ b/options.c
@@ -99,8 +99,6 @@ int recurse = 0;
 int allow_inc_recurse = 1;
 int xfer_dirs = -1;
 int am_daemon = 0;
-int do_stats = 0;
-int do_progress = 0;
 int connect_timeout = 0;
 int keep_partial = 0;
 int safe_symlinks = 0;
@@ -178,7 +176,6 @@ 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;
 int log_before_transfer = 0;
@@ -199,6 +196,93 @@ char *iconv_opt = ICONV_OPTION;
 
 struct chmod_mode_struct *chmod_modes = NULL;
 
+static 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",
+};
+
+#define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1)
+
+static char *info_verbosity[MAX_VERBOSITY] = {
+       /*0*/ NULL,
+       /*1*/ "copy,del,flist,misc,name,stats,symsafe",
+       /*2*/ "backup,misc2,mount,name2,remove,skip",
+};
+
+#define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */
+
+short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG];
+
+#define DEFAULT_PRIORITY 0     /* Default/implied/--verbose set values. */
+#define HELP_PRIORITY 1                /* The help output uses this level. */
+#define USER_PRIORITY 2                /* User-specified via --info or --debug */
+#define LIMIT_PRIORITY 3       /* Overriding priority when limiting values. */
+
+#define W_CLI (1<<0)   /* client side */
+#define W_SRV (1<<1)   /* server side */
+#define W_SND (1<<2)   /* sending side */
+#define W_REC (1<<3)   /* receiving side */
+
+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. */
+};
+
+#define INFO_WORD(flag, where, help) { #flag, help, INFO_##flag, where, 0 }
+
+static struct output_struct info_words[] = {
+       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(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"),
+       INFO_WORD(REMOVE, W_SND, "Mention files removed on the sending side"),
+       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 }
+};
+
+#define DEBUG_WORD(flag, where, help) { #flag, help, DEBUG_##flag, where, 0 }
+
+static struct output_struct debug_words[] = {
+       DEBUG_WORD(ACL, W_SND|W_REC, "Debug extra ACL info"),
+       DEBUG_WORD(BACKUP, W_REC, "Debug backup actions (levels 1-2)"),
+       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(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(HLINK, W_SND|W_REC, "Debug hard-link actions"),
+       DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv (character conversion)"),
+       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 }
+};
+
+static int verbose = 0;
+static int do_stats = 0;
+static int do_progress = 0;
 static int daemon_opt;   /* sets am_daemon after option error-reporting */
 static int omit_dir_times = 0;
 static int F_option_cnt = 0;
@@ -216,6 +300,252 @@ static char tmp_partialdir[] = ".~tmp~";
  * address, or a hostname. **/
 char *bind_address;
 
+static void output_item_help(struct output_struct *words);
+
+/* This constructs a string that represents all the options set for either
+ * 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)
+{
+       char *str = words == info_words ? "--info=" : "--debug=";
+       int j, counts[MAX_OUT_LEVEL+1], pos, skipped = 0, len = 0, max = 0, lev = 0;
+       int word_count = words == info_words ? COUNT_INFO : COUNT_DEBUG;
+       char *buf;
+
+       memset(counts, 0, sizeof counts);
+
+       for (j = 0; words[j].name; j++) {
+               if (words[j].flag != j) {
+                       rprintf(FERROR, "rsync: internal error on %s%s: %d != %d\n",
+                               words == info_words ? "INFO_" : "DEBUG_",
+                               words[j].name, words[j].flag, j);
+                       exit_cleanup(RERR_UNSUPPORTED);
+               }
+               if (!(words[j].where & where))
+                       continue;
+               if (words[j].priority == DEFAULT_PRIORITY) {
+                       /* Implied items don't need to be mentioned. */
+                       skipped++;
+                       continue;
+               }
+               len += len ? 1 : strlen(str);
+               len += strlen(words[j].name);
+               len += levels[j] == 1 ? 0 : 1;
+
+               if (words[j].priority == HELP_PRIORITY)
+                       continue; /* no abbreviating for help */
+
+               assert(levels[j] <= MAX_OUT_LEVEL);
+               if (++counts[levels[j]] > max) {
+                       /* Determine which level has the most items. */
+                       lev = levels[j];
+                       max = counts[lev];
+               }
+       }
+
+       /* Sanity check the COUNT_* define against the length of the table. */
+       if (j != word_count) {
+               rprintf(FERROR, "rsync: internal error: %s is wrong! (%d != %d)\n",
+                       words == info_words ? "COUNT_INFO" : "COUNT_DEBUG",
+                       j, word_count);
+               exit_cleanup(RERR_UNSUPPORTED);
+       }
+
+       if (!len)
+               return NULL;
+
+       len++;
+       if (!(buf = new_array(char, len)))
+               out_of_memory("make_output_option");
+       pos = 0;
+
+       if (skipped || max < 5)
+               lev = -1;
+       else {
+               if (lev == 0)
+                       pos += snprintf(buf, len, "%sNONE", str);
+               else if (lev == 1)
+                       pos += snprintf(buf, len, "%sALL", str);
+               else
+                       pos += snprintf(buf, len, "%sALL%d", str, lev);
+       }
+
+       for (j = 0; words[j].name && pos < len; j++) {
+               if (words[j].priority == DEFAULT_PRIORITY || levels[j] == lev || !(words[j].where & where))
+                       continue;
+               if (pos)
+                       buf[pos++] = ',';
+               else
+                       pos += strlcpy(buf+pos, str, len-pos);
+               if (pos < len)
+                       pos += strlcpy(buf+pos, words[j].name, len-pos);
+               /* Level 1 is implied by the name alone. */
+               if (levels[j] != 1 && pos < len)
+                       buf[pos++] = '0' + levels[j];
+       }
+
+       buf[pos] = '\0';
+
+       return buf;
+}
+
+static void parse_output_words(struct output_struct *words, short *levels,
+                              const char *str, int priority)
+{
+       const char *s;
+       int j, len, lev;
+
+       if (!str)
+               return;
+
+       while (*str) {
+               if ((s = strchr(str, ',')) != NULL)
+                       len = s++ - str;
+               else
+                       len = strlen(str);
+               while (len && isDigit(str+len-1))
+                       len--;
+               lev = isDigit(str+len) ? atoi(str+len) : 1;
+               if (lev > MAX_OUT_LEVEL)
+                       lev = MAX_OUT_LEVEL;
+               if (len == 4 && strncasecmp(str, "help", 4) == 0) {
+                       output_item_help(words);
+                       exit_cleanup(0);
+               }
+               if (len == 4 && strncasecmp(str, "none", 4) == 0)
+                       len = lev = 0;
+               else if (len == 3 && strncasecmp(str, "all", 3) == 0)
+                       len = 0;
+               for (j = 0; words[j].name; j++) {
+                       if (!len
+                        || (strncasecmp(str, words[j].name, len) == 0 && !words[j].name[len])) {
+                               if (priority >= words[j].priority) {
+                                       words[j].priority = priority;
+                                       levels[j] = lev;
+                               }
+                               if (len)
+                                       break;
+                       }
+               }
+               if (len && !words[j].name) {
+                       rprintf(FERROR, "Unknown %s item: %.*s\n", words[j].help, len, str);
+                       exit_cleanup(RERR_SYNTAX);
+               }
+               if (!s)
+                       break;
+               str = s;
+       }
+}
+
+/* Tell the user what all the info or debug flags mean. */
+static void output_item_help(struct output_struct *words)
+{
+       short *levels = words == info_words ? info_levels : debug_levels;
+       char buf[128], *opt, *fmt = "%-10s %s\n";
+       int j;
+
+       rprintf(FINFO, "Use OPT or OPT1 for level 1 output, OPT2 for level 2, etc.; OPT0 silences.\n");
+       rprintf(FINFO, "\n");
+       for (j = 0; words[j].name; j++)
+               rprintf(FINFO, fmt, words[j].name, words[j].help);
+       rprintf(FINFO, "\n");
+
+       snprintf(buf, sizeof buf, "Set all %s options (e.g. all%d)",
+                words[j].help, MAX_OUT_LEVEL);
+       rprintf(FINFO, fmt, "ALL", buf);
+
+       snprintf(buf, sizeof buf, "Silence all %s options (same as all0)",
+                words[j].help);
+       rprintf(FINFO, fmt, "NONE", buf);
+
+       rprintf(FINFO, fmt, "HELP", "Output this help message");
+       rprintf(FINFO, "\n");
+       rprintf(FINFO, "Options added for each increase in verbose level:\n");
+
+       for (j = 1; j <= MAX_VERBOSITY; j++) {
+               reset_output_levels();
+               if (words == info_words)
+                       parse_output_words(info_words, levels, info_verbosity[j], HELP_PRIORITY);
+               else
+                       parse_output_words(debug_words, levels, debug_verbosity[j], HELP_PRIORITY);
+               opt = make_output_option(words, levels, W_CLI|W_SRV|W_SND|W_REC);
+               if (opt) {
+                       rprintf(FINFO, "%d) %s\n", j, strchr(opt, '=')+1);
+                       free(opt);
+               }
+       }
+
+       reset_output_levels();
+}
+
+/* The --verbose option now sets info+debug flags. */
+static void set_output_verbosity(int level, int priority)
+{
+       int j;
+
+       if (level > MAX_VERBOSITY)
+               level = MAX_VERBOSITY;
+
+       for (j = 1; j <= level; j++) {
+               parse_output_words(info_words, info_levels, info_verbosity[j], priority);
+               parse_output_words(debug_words, debug_levels, debug_verbosity[j], priority);
+       }
+}
+
+/* Limit the info+debug flag levels given a verbose-option level limit. */
+void limit_output_verbosity(int level)
+{
+       short info_limits[COUNT_INFO], debug_limits[COUNT_DEBUG];
+       int j;
+
+       if (level > MAX_VERBOSITY)
+               return;
+
+       memset(info_limits, 0, sizeof info_limits);
+       memset(debug_limits, 0, sizeof debug_limits);
+
+       /* Compute the level limits in the above arrays. */
+       for (j = 1; j <= level; j++) {
+               parse_output_words(info_words, info_limits, info_verbosity[j], LIMIT_PRIORITY);
+               parse_output_words(debug_words, debug_limits, debug_verbosity[j], LIMIT_PRIORITY);
+       }
+
+       for (j = 0; j < COUNT_INFO; j++) {
+               if (info_levels[j] > info_limits[j])
+                       info_levels[j] = info_limits[j];
+       }
+
+       for (j = 0; j < COUNT_DEBUG; j++) {
+               if (debug_levels[j] > debug_limits[j])
+                       debug_levels[j] = debug_limits[j];
+       }
+}
+
+void reset_output_levels(void)
+{
+       int j;
+
+       memset(info_levels, 0, sizeof info_levels);
+       memset(debug_levels, 0, sizeof debug_levels);
+
+       for (j = 0; j < COUNT_INFO; j++)
+               info_words[j].priority = DEFAULT_PRIORITY;
+
+       for (j = 0; j < COUNT_DEBUG; j++)
+               debug_words[j].priority = DEFAULT_PRIORITY;
+}
+
+void negate_output_levels(void)
+{
+       int j;
+
+       for (j = 0; j < COUNT_INFO; j++)
+               info_levels[j] *= -1;
+
+       for (j = 0; j < COUNT_DEBUG; j++)
+               debug_levels[j] *= -1;
+}
 
 static void print_rsync_version(enum logcode f)
 {
@@ -318,6 +648,8 @@ void usage(enum logcode F)
   rprintf(F,"\n");
   rprintf(F,"Options\n");
   rprintf(F," -v, --verbose               increase verbosity\n");
+  rprintf(F,"     --info=FLAGS            fine-grained informational verbosity\n");
+  rprintf(F,"     --debug=FLAGS           fine-grained debug verbosity\n");
   rprintf(F," -q, --quiet                 suppress non-error messages\n");
   rprintf(F,"     --no-motd               suppress daemon-mode MOTD (see manpage caveat)\n");
   rprintf(F," -c, --checksum              skip based on checksum, not mod-time & size\n");
@@ -451,7 +783,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
       OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
       OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
-      OPT_NO_D, OPT_APPEND, OPT_NO_ICONV,
+      OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG,
       OPT_SERVER, OPT_REFUSED_BASE = 9000};
 
 static struct poptOption long_options[] = {
@@ -461,6 +793,8 @@ static struct poptOption long_options[] = {
   {"verbose",         'v', POPT_ARG_NONE,   0, 'v', 0, 0 },
   {"no-verbose",       0,  POPT_ARG_VAL,    &verbose, 0, 0, 0 },
   {"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 },
   {"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 },
@@ -1254,6 +1588,16 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        }
                        break;
 
+               case OPT_INFO:
+                       arg = poptGetOptArg(pc);
+                       parse_output_words(info_words, info_levels, arg, USER_PRIORITY);
+                       break;
+
+               case OPT_DEBUG:
+                       arg = poptGetOptArg(pc);
+                       parse_output_words(debug_words, debug_levels, arg, USER_PRIORITY);
+                       break;
+
                case OPT_HELP:
                        usage(FINFO);
                        exit_cleanup(0);
@@ -1307,6 +1651,13 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                exit_cleanup(0);
        }
 
+       set_output_verbosity(verbose, DEFAULT_PRIORITY);
+
+       if (do_stats && !am_server) {
+               parse_output_words(info_words, info_levels,
+                       verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY);
+       }
+
 #ifdef ICONV_OPTION
        if (iconv_opt && protect_args != 2) {
                if (!am_server && strcmp(iconv_opt, "-") == 0)
@@ -1523,7 +1874,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        backup_dir_buf[backup_dir_len++] = '/';
                        backup_dir_buf[backup_dir_len] = '\0';
                }
-               if (verbose > 1 && !am_sender)
+               if (INFO_GTE(BACKUP, 1) && !am_sender)
                        rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
        } else if (!backup_suffix_len && (!am_server || !am_sender)) {
                snprintf(err_buf, sizeof err_buf,
@@ -1558,11 +1909,10 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                log_before_transfer = !am_server;
        }
 
-       if (do_progress) {
-               if (am_server)
-                       do_progress = 0;
-               else if (!verbose && !log_before_transfer && !am_server)
-                       verbose = 1;
+       if (do_progress && !am_server) {
+               if (!log_before_transfer && INFO_EQ(NAME, 0))
+                       parse_output_words(info_words, info_levels, "name", DEFAULT_PRIORITY);
+               parse_output_words(info_words, info_levels, "flist2,progress", DEFAULT_PRIORITY);
        }
 
        if (dry_run)
@@ -1570,7 +1920,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
 
        set_io_timeout(io_timeout);
 
-       if (verbose && !stdout_format) {
+       if (INFO_GTE(NAME, 1) && !stdout_format) {
                stdout_format = "%n%L";
                log_before_transfer = !am_server;
        }
@@ -1733,6 +2083,7 @@ void server_options(char **args, int *argc_p)
 {
        static char argstr[64];
        int ac = *argc_p;
+       short where;
        char *arg;
        int i, x;
 
@@ -1860,13 +2211,13 @@ void server_options(char **args, int *argc_p)
 #endif
        }
 
-       argstr[x] = '\0';
-
-       if (x > (int)sizeof argstr) { /* Not possible... */
+       if (x >= (int)sizeof argstr) { /* Not possible... */
                rprintf(FERROR, "argstr overflow in server_options().\n");
                exit_cleanup(RERR_MALLOC);
        }
 
+       argstr[x] = '\0';
+
        args[ac++] = argstr;
 
 #ifdef ICONV_OPTION
@@ -2049,7 +2400,6 @@ void server_options(char **args, int *argc_p)
                         *   and it may be an older version that doesn't know this
                         *   option, so don't send it if client is the sender.
                         */
-                       int i;
                        for (i = 0; i < basis_dir_cnt; i++) {
                                args[ac++] = dest_option;
                                args[ac++] = basis_dir[i];
@@ -2057,6 +2407,16 @@ void server_options(char **args, int *argc_p)
                }
        }
 
+       /* What flags do we need to send to the other side? */
+       where = (am_server ? W_CLI : W_SRV) | (am_sender ? W_REC : W_SND);
+       arg = make_output_option(info_words, info_levels, where);
+       if (arg)
+               args[ac++] = arg;
+
+       arg = make_output_option(debug_words, debug_levels, where);
+       if (arg)
+               args[ac++] = arg;
+
        if (append_mode) {
                if (append_mode > 1)
                        args[ac++] = "--append";
diff --git a/pipe.c b/pipe.c
index f32d63e..755da54 100644 (file)
--- a/pipe.c
+++ b/pipe.c
@@ -51,7 +51,7 @@ pid_t piped_child(char **command, int *f_in, int *f_out)
        int to_child_pipe[2];
        int from_child_pipe[2];
 
-       if (verbose >= 2)
+       if (DEBUG_GTE(CMD, 1))
                print_child_argv("opening connection using:", command);
 
        if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
index 25033b8..afd8ef6 100644 (file)
@@ -24,6 +24,7 @@
 
 extern int am_server;
 extern int need_unsorted_flist;
+extern int output_needs_newline;
 extern struct stats stats;
 extern struct file_list *cur_flist;
 
@@ -40,8 +41,6 @@ struct progress_history {
        OFF_T ofs;
 };
 
-int progress_is_active = 0;
-
 static struct progress_history ph_start;
 static struct progress_history ph_list[PROGRESS_HISTORY_SECS];
 static int newest_hpos, oldest_hpos;
@@ -66,16 +65,26 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
 {
        char rembuf[64], eol[128];
        const char *units;
-       int pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
        unsigned long diff;
        double rate, remain;
+       int pct;
 
        if (is_last) {
-               snprintf(eol, sizeof eol,
+               int len = snprintf(eol, sizeof eol,
                        " (xfer#%d, to-check=%d/%d)\n",
                        stats.num_transferred_files,
                        stats.num_files - current_file_index - 1,
                        stats.num_files);
+               if (INFO_GTE(PROGRESS, 2)) {
+                       static int last_len = 0;
+                       /* Drop \n and pad with spaces if line got shorter. */
+                       if (last_len < --len)
+                               last_len = len;
+                       eol[last_len] = '\0';
+                       while (last_len > len)
+                               eol[--last_len] = ' ';
+                       is_last = 0;
+               }
                /* Compute stats based on the starting info. */
                if (!ph_start.time.tv_sec
                    || !(diff = msdiff(&ph_start.time, now)))
@@ -112,18 +121,21 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now,
                         (int) remain % 60);
        }
 
-       progress_is_active = 0;
+       output_needs_newline = 0;
+       pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
        rprintf(FCLIENT, "\r%12s %3d%% %7.2f%s %s%s",
                human_num(ofs), pct, rate, units, rembuf, eol);
        if (!is_last) {
-               progress_is_active = 1;
-               fflush(stdout);
+               output_needs_newline = 1;
+               rflush(FCLIENT);
        }
 }
 
 void set_current_file_index(struct file_struct *file, int ndx)
 {
-       if (need_unsorted_flist)
+       if (!file)
+               current_file_index = cur_flist->used + cur_flist->ndx_start - 1;
+       else if (need_unsorted_flist)
                current_file_index = flist_find(cur_flist, file) + cur_flist->ndx_start;
        else
                current_file_index = ndx;
@@ -135,9 +147,14 @@ void end_progress(OFF_T size)
        if (!am_server) {
                struct timeval now;
                gettimeofday(&now, NULL);
-               rprint_progress(size, size, &now, True);
+               if (INFO_GTE(PROGRESS, 2)) {
+                       rprint_progress(stats.total_transferred_size,
+                                       stats.total_size, &now, True);
+               } else {
+                       rprint_progress(size, size, &now, True);
+                       memset(&ph_start, 0, sizeof ph_start);
+               }
        }
-       memset(&ph_start, 0, sizeof ph_start);
 }
 
 void show_progress(OFF_T ofs, OFF_T size)
@@ -193,5 +210,9 @@ void show_progress(OFF_T ofs, OFF_T size)
                return;
 #endif
 
-       rprint_progress(ofs, size, &now, False);
+       if (INFO_GTE(PROGRESS, 2)) {
+               rprint_progress(stats.total_transferred_size,
+                               stats.total_size, &now, False);
+       } else
+               rprint_progress(ofs, size, &now, False);
 }
index ce6b739..2ba1ab9 100644 (file)
 
 #include "rsync.h"
 
-extern int verbose;
 extern int dry_run;
 extern int do_xfers;
 extern int am_server;
-extern int do_progress;
 extern int inc_recurse;
 extern int log_before_transfer;
 extern int stdout_format_has_i;
@@ -180,7 +178,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
        if (fd_r >= 0 && size_r > 0) {
                int32 read_size = MAX(sum.blength * 2, 16*1024);
                mapbuf = map_file(fd_r, size_r, read_size, sum.blength);
-               if (verbose > 2) {
+               if (DEBUG_GTE(CHKSUM, 2)) {
                        rprintf(FINFO, "recv mapped %s of size %.0f\n",
                                fname_r, (double)size_r);
                }
@@ -196,7 +194,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        sum.flength -= sum.blength - sum.remainder;
                if (append_mode == 2) {
                        for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) {
-                               if (do_progress)
+                               if (INFO_GTE(PROGRESS, 1))
                                        show_progress(offset, total_size);
                                sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE),
                                           CHUNK_SIZE);
@@ -204,7 +202,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        }
                        if (offset < sum.flength) {
                                int32 len = (int32)(sum.flength - offset);
-                               if (do_progress)
+                               if (INFO_GTE(PROGRESS, 1))
                                        show_progress(offset, total_size);
                                sum_update(map_ptr(mapbuf, offset, len), len);
                        }
@@ -218,11 +216,11 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
        }
 
        while ((i = recv_token(f_in, &data)) != 0) {
-               if (do_progress)
+               if (INFO_GTE(PROGRESS, 1))
                        show_progress(offset, total_size);
 
                if (i > 0) {
-                       if (verbose > 3) {
+                       if (DEBUG_GTE(CHKSUM, 3)) {
                                rprintf(FINFO,"data recv %d at %.0f\n",
                                        i,(double)offset);
                        }
@@ -246,7 +244,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
 
                stats.matched_data += len;
 
-               if (verbose > 3) {
+               if (DEBUG_GTE(CHKSUM, 3)) {
                        rprintf(FINFO,
                                "chunk[%d] of size %ld at %.0f offset=%.0f\n",
                                i, (long)len, (double)offset2, (double)offset);
@@ -288,7 +286,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                ftruncate(fd, offset);
 #endif
 
-       if (do_progress)
+       if (INFO_GTE(PROGRESS, 1))
                end_progress(total_size);
 
        if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
@@ -304,7 +302,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                unmap_file(mapbuf);
 
        read_buf(f_in, file_sum2, sum_len);
-       if (verbose > 2)
+       if (DEBUG_GTE(CHKSUM, 2))
                rprintf(FINFO,"got file_sum\n");
        if (fd != -1 && memcmp(file_sum1, file_sum2, sum_len) != 0)
                return 0;
@@ -328,7 +326,7 @@ static void handle_delayed_updates(char *local_name)
                if ((partialptr = partial_dir_fname(fname)) != NULL) {
                        if (make_backups > 0 && !make_backup(fname))
                                continue;
-                       if (verbose > 2) {
+                       if (DEBUG_GTE(RECV, 1)) {
                                rprintf(FINFO, "renaming %s to %s\n",
                                        partialptr, fname);
                        }
@@ -396,7 +394,7 @@ int recv_files(int f_in, char *local_name)
 #endif
        int ndx, recv_ok;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(RECV, 1))
                rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
 
        if (delay_updates)
@@ -409,6 +407,10 @@ int recv_files(int f_in, char *local_name)
                ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
                                         xname, &xlen);
                if (ndx == NDX_DONE) {
+                       if (!am_server && INFO_GTE(PROGRESS, 2) && cur_flist) {
+                               set_current_file_index(NULL, 0);
+                               end_progress(0);
+                       }
                        if (inc_recurse && first_flist) {
                                flist_free(first_flist);
                                if (first_flist)
@@ -423,7 +425,7 @@ int recv_files(int f_in, char *local_name)
                        }
                        if (++phase > max_phase)
                                break;
-                       if (verbose > 2)
+                       if (DEBUG_GTE(RECV, 1))
                                rprintf(FINFO, "recv_files phase=%d\n", phase);
                        if (phase == 2 && delay_updates)
                                handle_delayed_updates(local_name);
@@ -437,7 +439,7 @@ int recv_files(int f_in, char *local_name)
                        file = dir_flist->files[cur_flist->parent_ndx];
                fname = local_name ? local_name : f_name(file, fbuf);
 
-               if (verbose > 2)
+               if (DEBUG_GTE(RECV, 1))
                        rprintf(FINFO, "recv_files(%s)\n", fname);
 
 #ifdef SUPPORT_XATTRS
@@ -482,7 +484,7 @@ int recv_files(int f_in, char *local_name)
                        }
                }
 
-               if (!am_server && do_progress)
+               if (!am_server && INFO_GTE(PROGRESS, 1))
                        set_current_file_index(file, ndx);
                stats.num_transferred_files++;
                stats.total_transferred_size += F_LENGTH(file);
@@ -671,7 +673,7 @@ int recv_files(int f_in, char *local_name)
                /* log the transfer */
                if (log_before_transfer)
                        log_item(FCLIENT, file, &initial_stats, iflags, NULL);
-               else if (!am_server && verbose && do_progress)
+               else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1))
                        rprintf(FINFO, "%s\n", fname);
 
                /* recv file data */
@@ -722,7 +724,7 @@ int recv_files(int f_in, char *local_name)
                        break;
                case 0: {
                        enum logcode msgtype = redoing ? FERROR_XFER : FWARNING;
-                       if (msgtype == FERROR_XFER || verbose) {
+                       if (msgtype == FERROR_XFER || INFO_GTE(NAME, 1)) {
                                char *errstr, *redostr, *keptstr;
                                if (!(keep_partial && partialptr) && !inplace)
                                        keptstr = "discarded";
@@ -762,7 +764,7 @@ int recv_files(int f_in, char *local_name)
        if (phase == 2 && delay_updates) /* for protocol_version < 29 */
                handle_delayed_updates(local_name);
 
-       if (verbose > 2)
+       if (DEBUG_GTE(RECV, 1))
                rprintf(FINFO,"recv_files finished\n");
 
        return 0;
diff --git a/rsync.c b/rsync.c
index 85244c8..734a373 100644 (file)
--- a/rsync.c
+++ b/rsync.c
@@ -27,7 +27,6 @@
 #include <langinfo.h>
 #endif
 
-extern int verbose;
 extern int dry_run;
 extern int preserve_acls;
 extern int preserve_xattrs;
@@ -84,7 +83,7 @@ void setup_iconv(void)
                /* It's OK if this fails... */
                ic_chck = iconv_open(defset, defset);
 
-               if (verbose > 3) {
+               if (DEBUG_GTE(ICONV, 1)) {
                        if (ic_chck == (iconv_t)-1) {
                                rprintf(FINFO,
                                        "note: iconv_open(\"%s\", \"%s\") failed (%d)"
@@ -126,7 +125,7 @@ void setup_iconv(void)
                exit_cleanup(RERR_UNSUPPORTED);
        }
 
-       if (verbose > 1) {
+       if (INFO_GTE(MISC, 2)) {
                rprintf(FINFO, "%s charset: %s\n",
                        am_server ? "server" : "client",
                        *charset ? charset : "[LOCALE]");
@@ -218,7 +217,7 @@ void send_protected_args(int fd, char *args[])
 
        for (i = 0; args[i]; i++) {} /* find first NULL */
        args[i] = "rsync"; /* set a new arg0 */
-       if (verbose > 1)
+       if (DEBUG_GTE(CMD, 1))
                print_child_argv("protected args:", args + i + 1);
        do {
 #ifdef ICONV_OPTION
@@ -247,7 +246,7 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
        int len, iflags = 0;
        struct file_list *flist;
        uchar fnamecmp_type = FNAMECMP_FNAME;
-       int ndx, save_verbose = verbose;
+       int ndx;
 
   read_loop:
        while (1) {
@@ -275,17 +274,17 @@ int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
                }
 
                /* Send everything read from f_in to msg_fd_out. */
-               if (verbose > 3) {
+               if (DEBUG_GTE(FLIST, 2)) {
                        rprintf(FINFO, "[%s] receiving flist for dir %d\n",
                                who_am_i(), ndx);
                }
-               verbose = 0;
+               negate_output_levels(); /* turn off all info/debug output */
                send_msg_int(MSG_FLIST, ndx);
                start_flist_forward(f_in);
                flist = recv_file_list(f_in);
                flist->parent_ndx = ndx;
                stop_flist_forward();
-               verbose = save_verbose;
+               negate_output_levels(); /* restore info/debug output */
        }
 
        iflags = protocol_version >= 29 ? read_shortint(f_in)
@@ -448,7 +447,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
        } else
 #endif
        if (change_uid || change_gid) {
-               if (verbose > 2) {
+               if (DEBUG_GTE(OWN, 1)) {
                        if (change_uid) {
                                rprintf(FINFO,
                                        "set uid of %s from %u to %u\n",
@@ -507,7 +506,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
        }
 #endif
 
-       if (verbose > 1 && flags & ATTRS_REPORT) {
+       if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) {
                if (updated)
                        rprintf(FCLIENT, "%s\n", fname);
                else
@@ -555,7 +554,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
        const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL;
 
        if (inplace) {
-               if (verbose > 2)
+               if (DEBUG_GTE(RECV, 1))
                        rprintf(FINFO, "finishing %s\n", fname);
                fnametmp = fname;
                goto do_set_file_attrs;
@@ -573,7 +572,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
                       ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
 
        /* move tmp file over real file */
-       if (verbose > 2)
+       if (DEBUG_GTE(RECV, 1))
                rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
        ret = robust_rename(fnametmp, fname, temp_copy_name,
                            file->mode & INITACCESSPERMS);
diff --git a/rsync.h b/rsync.h
index 77f9b3a..fdc7a03 100644 (file)
--- a/rsync.h
+++ b/rsync.h
@@ -1120,7 +1120,51 @@ size_t strlcat(char *d, const char *s, size_t bufsize);
 #define FD_ZERO(fdsetp) memset(fdsetp, 0, sizeof (fd_set))
 #endif
 
-extern int verbose;
+extern short info_levels[], debug_levels[];
+
+#define INFO_GTE(flag, lvl) (info_levels[INFO_##flag] >= (lvl))
+#define INFO_EQ(flag, lvl) (info_levels[INFO_##flag] == (lvl))
+#define DEBUG_GTE(flag, lvl) (debug_levels[DEBUG_##flag] >= (lvl))
+#define DEBUG_EQ(flag, lvl) (debug_levels[DEBUG_##flag] == (lvl))
+
+#define INFO_BACKUP 0
+#define INFO_COPY (INFO_BACKUP+1)
+#define INFO_DEL (INFO_COPY+1)
+#define INFO_FLIST (INFO_DEL+1)
+#define INFO_MISC (INFO_FLIST+1)
+#define INFO_MOUNT (INFO_MISC+1)
+#define INFO_NAME (INFO_MOUNT+1)
+#define INFO_PROGRESS (INFO_NAME+1)
+#define INFO_REMOVE (INFO_PROGRESS+1)
+#define INFO_SKIP (INFO_REMOVE+1)
+#define INFO_STATS (INFO_SKIP+1)
+#define INFO_SYMSAFE (INFO_STATS+1)
+
+#define COUNT_INFO (INFO_SYMSAFE+1)
+
+#define DEBUG_ACL 0
+#define DEBUG_BACKUP (DEBUG_ACL+1)
+#define DEBUG_BIND (DEBUG_BACKUP+1)
+#define DEBUG_CHDIR (DEBUG_BIND+1)
+#define DEBUG_CONNECT (DEBUG_CHDIR+1)
+#define DEBUG_CHKSUM (DEBUG_CONNECT+1)
+#define DEBUG_CMD (DEBUG_CHKSUM+1)
+#define DEBUG_DEL (DEBUG_CMD+1)
+#define DEBUG_DUP (DEBUG_DEL+1)
+#define DEBUG_EXIT (DEBUG_DUP+1)
+#define DEBUG_FILTER (DEBUG_EXIT+1)
+#define DEBUG_FLIST (DEBUG_FILTER+1)
+#define DEBUG_FUZZY (DEBUG_FLIST+1)
+#define DEBUG_GENR (DEBUG_FUZZY+1)
+#define DEBUG_HLINK (DEBUG_GENR+1)
+#define DEBUG_ICONV (DEBUG_HLINK+1)
+#define DEBUG_OWN (DEBUG_ICONV+1)
+#define DEBUG_PROTO (DEBUG_OWN+1)
+#define DEBUG_RECV (DEBUG_PROTO+1)
+#define DEBUG_SEND (DEBUG_RECV+1)
+#define DEBUG_TIME (DEBUG_SEND+1)
+
+#define COUNT_DEBUG (DEBUG_TIME+1)
 
 #ifndef HAVE_INET_NTOP
 const char *inet_ntop(int af, const void *src, char *dst, size_t size);
index 3377312..1b30c7a 100644 (file)
--- a/rsync.yo
+++ b/rsync.yo
@@ -314,6 +314,8 @@ manpagesection(OPTIONS SUMMARY)
 Here is a short summary of the options available in rsync. Please refer
 to the detailed description below for a complete description.  verb(
  -v, --verbose               increase verbosity
+     --info=FLAGS            fine-grained informational verbosity
+     --debug=FLAGS           fine-grained debug verbosity
  -q, --quiet                 suppress non-error messages
      --no-motd               suppress daemon-mode MOTD (see caveat)
  -c, --checksum              skip based on checksum, not mod-time & size
@@ -465,23 +467,61 @@ dit(bf(--version)) print the rsync version number and exit.
 dit(bf(-v, --verbose)) This option increases the amount of information you
 are given during the transfer.  By default, rsync works silently. A
 single bf(-v) will give you information about what files are being
-transferred and a brief summary at the end. Two bf(-v) flags will give you
+transferred and a brief summary at the end. Two bf(-v) options will give you
 information on what files are being skipped and slightly more
-information at the end. More than two bf(-v) flags should only be used if
+information at the end. More than two bf(-v) options should only be used if
 you are debugging rsync.
 
-Note that the names of the transferred files that are output are done using
-a default bf(--out-format) of "%n%L", which tells you just the name of the
-file and, if the item is a link, where it points.  At the single bf(-v)
-level of verbosity, this does not mention when a file gets its attributes
-changed.  If you ask for an itemized list of changed attributes (either
-bf(--itemize-changes) or adding "%i" to the bf(--out-format) setting), the
-output (on the client) increases to mention all items that are changed in
-any way.  See the bf(--out-format) option for more details.
+In a modern rsync, the bf(-v) option is equivalent to the setting of groups
+of bf(--info) and bf(--debug) options.  You can choose to use these newer
+options in addition to, or in place of using bf(--verbose), as any
+fine-grained settings override the implied settings of bf(-v).  Both
+bf(--info) and bf(--debug) have a way to ask for help that tells you
+exactly what flags are set for each increase in verbosity.
+
+dit(bf(--info=FLAGS))
+This option lets you have fine-grained control over the
+information
+output you want to see.  An individual flag name may be followed by a level
+number, with 0 meaning to silence that output, 1 being the default output
+level, and higher numbers increasing the output of that flag (for those
+that support higher levels).  Use
+bf(--info=help)
+to see all the available flag names, what they output, and what flag names
+are added for each increase in the verbose level.  Some examples:
+
+verb(    rsync -a --info=progress2 src/ dest/
+    rsync -avv --info=stats2,misc1,flist0 src/ dest/ )
+
+Note that bf(--info=name)'s output is affected by the bf(--out-format) and
+bf(--itemize-changes) (bf(-i)) options.  See those options for more
+information on what is output and when.
+
+This option was added to 3.1.0, so an older rsync on the server side might
+reject your attempts at fine-grained control (if one or more flags needed
+to be send to the server and the server was too old to understand them).
+
+dit(bf(--debug=FLAGS))
+This option lets you have fine-grained control over the
+debug
+output you want to see.  An individual flag name may be followed by a level
+number, with 0 meaning to silence that output, 1 being the default output
+level, and higher numbers increasing the output of that flag (for those
+that support higher levels).  Use
+bf(--debug=help)
+to see all the available flag names, what they output, and what flag names
+are added for each increase in the verbose level.  Some examples:
+
+verb(    rsync -avvv --debug=none src/ dest/
+    rsync -avA --del --debug=del2,acl src/ dest/ )
+
+This option was added to 3.1.0, so an older rsync on the server side might
+reject your attempts at fine-grained control (if one or more flags needed
+to be send to the server and the server was too old to understand them).
 
 dit(bf(-q, --quiet)) This option decreases the amount of information you
 are given during the transfer, notably suppressing information messages
-from the remote server. This flag is useful when invoking rsync from
+from the remote server. This option name is useful when invoking rsync from
 cron.
 
 dit(bf(--no-motd)) This option affects the information that is output
@@ -1756,22 +1796,22 @@ you are talking to a recent enough rsync that it logs deletions instead of
 outputting them as a verbose message).
 
 dit(bf(--out-format=FORMAT)) This allows you to specify exactly what the
-rsync client outputs to the user on a per-update basis.  The format is a text
-string containing embedded single-character escape sequences prefixed with
-a percent (%) character.  For a list of the possible escape characters, see
-the "log format" setting in the rsyncd.conf manpage.
-
-Specifying this option will mention each file, dir, etc. that gets updated
-in a significant way (a transferred file, a recreated symlink/device, or a
-touched directory).  In addition, if the itemize-changes escape (%i) is
-included in the string, the logging of names increases to mention any
-item that is changed in any way (as long as the receiving side is at least
-2.6.4).  See the bf(--itemize-changes) option for a description of the
-output of "%i".
-
-The bf(--verbose) option implies a format of "%n%L", but you can use
-bf(--out-format) without bf(--verbose) if you like, or you can override
-the format of its per-file output using this option.
+rsync client outputs to the user on a per-update basis.  The format is a
+text string containing embedded single-character escape sequences prefixed
+with a percent (%) character.   A default format of "%n%L" is assumed if
+either bf(--info=name) or bf(-v) is specified (this tells you just the name
+of the file and, if the item is a link, where it points).  For a full list
+of the possible escape characters, see the "log format" setting in the
+rsyncd.conf manpage.
+
+Specifying the bf(--out-format) option implies the bf(--info=name) option,
+which will mention each file, dir, etc. that gets updated in a significant
+way (a transferred file, a recreated symlink/device, or a touched
+directory).  In addition, if the itemize-changes escape (%i) is included in
+the string (e.g. if the bf(--itemize-changes) option was used), the logging
+of names increases to mention any item that is changed in any way (as long
+as the receiving side is at least 2.6.4).  See the bf(--itemize-changes)
+option for a description of the output of "%i".
 
 Rsync will output the out-format string prior to a file's transfer unless
 one of the transfer-statistic escapes is requested, in which case the
@@ -1804,7 +1844,9 @@ in the rsyncd.conf manpage.
 
 dit(bf(--stats)) This tells rsync to print a verbose set of statistics
 on the file transfer, allowing you to tell how effective rsync's delta-transfer
-algorithm is for your data.
+algorithm is for your data.  This option is equivalent to bf(--info=stats2)
+if combined with 0 or 1 bf(-v) options, or bf(--info=stats3) if combined
+with 2 or more bf(-v) options.
 
 The current statistics are as follows: quote(itemization(
   it() bf(Number of files) is the count of all "files" (in the generic
@@ -1977,7 +2019,9 @@ in place of the hide-filter (if that is more natural to you).
 dit(bf(--progress)) This option tells rsync to print information
 showing the progress of the transfer. This gives a bored user
 something to watch.
-Implies bf(--verbose) if it wasn't already specified.
+With a modern rsync this is the same as specifying
+bf(--info=flist2,name,progress), but any user-supplied settings for those
+info flags takes precedence (e.g. "--info=flist0 --progress").
 
 While rsync is transferring a regular file, it updates a progress line that
 looks like this:
@@ -2012,6 +2056,13 @@ dit(bf(-P)) The bf(-P) option is equivalent to bf(--partial) bf(--progress).  It
 purpose is to make it much easier to specify these two options for a long
 transfer that may be interrupted.
 
+There is also a bf(--info=progress2) option that outputs statistics based
+on the whole transfer, rather than individual files.  Use this flag without
+outputting a filename (e.g. avoid bf(-v) or specify bf(--info=name0) if you
+want to see how the transfer is doing without scrolling the screen with a
+lot of names.  (You don't need to specify the bf(--progress) option in
+order to use bf(--info=progress2).)
+
 dit(bf(--password-file)) This option allows you to provide a password in a
 file for accessing an rsync daemon.  The file must not be world readable.
 It should contain just the password as a single line.
index f772877..6aa5aeb 100644 (file)
--- a/sender.c
+++ b/sender.c
@@ -21,7 +21,6 @@
 
 #include "rsync.h"
 
-extern int verbose;
 extern int dry_run;
 extern int do_xfers;
 extern int am_server;
@@ -39,7 +38,6 @@ extern int protocol_version;
 extern int remove_source_files;
 extern int updating_basis_file;
 extern int make_backups;
-extern int do_progress;
 extern int inplace;
 extern int batch_fd;
 extern int write_batch;
@@ -71,7 +69,7 @@ static struct sum_struct *receive_sums(int f)
 
        s->sums = NULL;
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(CHKSUM, 3)) {
                rprintf(FINFO, "count=%.0f n=%ld rem=%ld\n",
                        (double)s->count, (long)s->blength, (long)s->remainder);
        }
@@ -105,7 +103,7 @@ static struct sum_struct *receive_sums(int f)
                if (allowed_lull && !(i % lull_mod))
                        maybe_send_keepalive();
 
-               if (verbose > 3) {
+               if (DEBUG_GTE(CHKSUM, 3)) {
                        rprintf(FINFO,
                                "chunk[%d] len=%d offset=%.0f sum1=%08x\n",
                                i, s->sums[i].len, (double)s->sums[i].offset,
@@ -140,7 +138,7 @@ void successful_send(int ndx)
        f_name(file, fname);
 
        if (do_unlink(fname) == 0) {
-               if (verbose > 1)
+               if (INFO_GTE(REMOVE, 1))
                        rprintf(FINFO, "sender removed %s\n", fname);
        } else
                rsyserr(FERROR, errno, "sender failed to remove %s", fname);
@@ -182,7 +180,7 @@ void send_files(int f_in, int f_out)
        int f_xfer = write_batch < 0 ? batch_fd : f_out;
        int ndx, j;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(SEND, 1))
                rprintf(FINFO, "send_files starting\n");
 
        while (1) {
@@ -193,6 +191,10 @@ void send_files(int f_in, int f_out)
                ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
                                         xname, &xlen);
                if (ndx == NDX_DONE) {
+                       if (!am_server && INFO_GTE(PROGRESS, 2) && cur_flist) {
+                               set_current_file_index(NULL, 0);
+                               end_progress(0);
+                       }
                        if (inc_recurse && first_flist) {
                                flist_free(first_flist);
                                if (first_flist) {
@@ -202,7 +204,7 @@ void send_files(int f_in, int f_out)
                        }
                        if (++phase > max_phase)
                                break;
-                       if (verbose > 2)
+                       if (DEBUG_GTE(SEND, 1))
                                rprintf(FINFO, "send_files phase=%d\n", phase);
                        write_ndx(f_out, NDX_DONE);
                        continue;
@@ -225,7 +227,7 @@ void send_files(int f_in, int f_out)
                        continue;
                f_name(file, fname);
 
-               if (verbose > 2)
+               if (DEBUG_GTE(SEND, 1))
                        rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname);
 
 #ifdef SUPPORT_XATTRS
@@ -265,7 +267,7 @@ void send_files(int f_in, int f_out)
                updating_basis_file = inplace && (protocol_version >= 29
                        ? fnamecmp_type == FNAMECMP_FNAME : make_backups <= 0);
 
-               if (!am_server && do_progress)
+               if (!am_server && INFO_GTE(PROGRESS, 1))
                        set_current_file_index(file, ndx);
                stats.num_transferred_files++;
                stats.total_transferred_size += F_LENGTH(file);
@@ -321,7 +323,7 @@ void send_files(int f_in, int f_out)
                } else
                        mbuf = NULL;
 
-               if (verbose > 2) {
+               if (DEBUG_GTE(CHKSUM, 2)) {
                        rprintf(FINFO, "send_files mapped %s%s%s of size %.0f\n",
                                path,slash,fname, (double)st.st_size);
                }
@@ -330,18 +332,18 @@ void send_files(int f_in, int f_out)
                                    fnamecmp_type, xname, xlen);
                write_sum_head(f_xfer, s);
 
-               if (verbose > 2)
+               if (DEBUG_GTE(CHKSUM, 2))
                        rprintf(FINFO, "calling match_sums %s%s%s\n", path,slash,fname);
 
                if (log_before_transfer)
                        log_item(FCLIENT, file, &initial_stats, iflags, NULL);
-               else if (!am_server && verbose && do_progress)
+               else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1))
                        rprintf(FCLIENT, "%s\n", fname);
 
                set_compression(fname);
 
                match_sums(f_xfer, s, mbuf, st.st_size);
-               if (do_progress)
+               if (INFO_GTE(PROGRESS, 1))
                        end_progress(st.st_size);
 
                log_item(log_code, file, &initial_stats, iflags, NULL);
@@ -359,7 +361,7 @@ void send_files(int f_in, int f_out)
 
                free_sums(s);
 
-               if (verbose > 2)
+               if (DEBUG_GTE(SEND, 1))
                        rprintf(FINFO, "sender finished %s%s%s\n", path,slash,fname);
 
                /* Flag that we actually sent this entry. */
@@ -368,7 +370,7 @@ void send_files(int f_in, int f_out)
        if (make_backups < 0)
                make_backups = -make_backups;
 
-       if (verbose > 2)
+       if (DEBUG_GTE(SEND, 1))
                rprintf(FINFO, "send files finished\n");
 
        match_report();
index 8d4a89d..2b3271c 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -232,7 +232,7 @@ int open_socket_out(char *host, int port, const char *bind_addr,
                }
                *cp++ = '\0';
                strlcpy(portbuf, cp, sizeof portbuf);
-               if (verbose >= 2) {
+               if (DEBUG_GTE(CONNECT, 1)) {
                        rprintf(FINFO, "connection via http proxy %s port %s\n",
                                h, portbuf);
                }
@@ -361,7 +361,7 @@ int open_socket_out_wrapped(char *host, int port, const char *bind_addr,
                *t = '\0';
        }
 
-       if (verbose >= 2) {
+       if (DEBUG_GTE(CONNECT, 1)) {
                rprintf(FINFO, "%sopening tcp connection to %s port %d\n",
                        prog ? "Using RSYNC_CONNECT_PROG instead of " : "",
                        host, port);
@@ -473,7 +473,7 @@ static int *open_socket_in(int type, int port, const char *bind_addr,
        /* Only output the socket()/bind() messages if we were totally
         * unsuccessful, or if the daemon is being run with -vv. */
        for (s = 0; s < ecnt; s++) {
-               if (!i || verbose > 1)
+               if (!i || DEBUG_GTE(BIND, 1))
                        rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0);
                free(errmsgs[s]);
        }
@@ -829,7 +829,7 @@ int sock_exec(const char *prog)
                rsyserr(FERROR, errno, "socketpair_tcp failed");
                return -1;
        }
-       if (verbose >= 2)
+       if (DEBUG_GTE(CMD, 1))
                rprintf(FINFO, "Running socket program: \"%s\"\n", prog);
        if (fork() == 0) {
                close(fd[0]);
index 44662bd..943185a 100644 (file)
@@ -27,9 +27,9 @@ int dry_run = 0;
 int am_root = 0;
 int read_only = 0;
 int list_only = 0;
-int verbose = 0;
 int preserve_perms = 0;
 int preserve_executability = 0;
+short info_levels[10], debug_levels[10];
 
 int
 main(int argc, char **argv)
index d7774bb..d4a8475 100644 (file)
@@ -2,4 +2,8 @@
 
 echo $0 running
 
-$RSYNC --version || exit 1
+$RSYNC --version || test_fail '--version output failed'
+
+$RSYNC --info=help || test_fail '--info=help output failed'
+
+$RSYNC --debug=help || test_fail '--debug=help output failed'
index e17fe5a..2947a5f 100644 (file)
@@ -268,7 +268,7 @@ log file = $logfile
 log format = %i %h [%a] %m (%u) %l %f%L
 transfer logging = yes
 exclude = ? foobar.baz
-max verbosity = 9
+max verbosity = 4
 uid = 0
 gid = 0
 
index 3d9c774..d9ca7a2 100644 (file)
--- a/uidlist.c
+++ b/uidlist.c
@@ -26,7 +26,6 @@
 #include "rsync.h"
 #include "io.h"
 
-extern int verbose;
 extern int am_root;
 extern int preserve_uid;
 extern int preserve_gid;
@@ -126,7 +125,7 @@ static int is_in_group(gid_t gid)
                }
                if (n == ngroups)
                        gidset[ngroups++] = mygid;
-               if (verbose > 3) {
+               if (DEBUG_GTE(OWN, 2)) {
                        int pos;
                        char *gidbuf = new_array(char, ngroups*21+32);
                        if (!gidbuf)
@@ -152,7 +151,7 @@ static int is_in_group(gid_t gid)
        static gid_t mygid = GID_NONE;
        if (mygid == GID_NONE) {
                mygid = MY_GID();
-               if (verbose > 3)
+               if (DEBUG_GTE(OWN, 2))
                        rprintf(FINFO, "process has gid %u\n", (unsigned)mygid);
        }
        return gid == mygid;
@@ -167,7 +166,7 @@ static struct idlist *recv_add_uid(uid_t id, const char *name)
 
        node = add_to_list(&uidlist, id, name, id2, 0);
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(OWN, 2)) {
                rprintf(FINFO, "uid %u(%s) maps to %u\n",
                        (unsigned)id, name ? name : "", (unsigned)id2);
        }
@@ -184,7 +183,7 @@ static struct idlist *recv_add_gid(gid_t id, const char *name)
        node = add_to_list(&gidlist, id, name, id2,
                !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
 
-       if (verbose > 3) {
+       if (DEBUG_GTE(OWN, 2)) {
                rprintf(FINFO, "gid %u(%s) maps to %u\n",
                        (unsigned)id, name ? name : "", (unsigned)id2);
        }
diff --git a/util.c b/util.c
index c71830b..0b3dc38 100644 (file)
--- a/util.c
+++ b/util.c
@@ -23,7 +23,6 @@
 #include "rsync.h"
 #include "ifuncs.h"
 
-extern int verbose;
 extern int dry_run;
 extern int module_id;
 extern int modify_window;
@@ -130,7 +129,7 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode)
                return 1;
 #endif
 
-       if (verbose > 2) {
+       if (DEBUG_GTE(TIME, 1)) {
                rprintf(FINFO, "set modtime of %s to (%ld) %s",
                        fname, (long)modtime,
                        asctime(localtime(&modtime)));
@@ -397,7 +396,7 @@ int robust_unlink(const char *fname)
                        counter = 1;
        } while ((rc = access(path, 0)) == 0 && counter != start);
 
-       if (verbose > 0) {
+       if (INFO_GTE(MISC, 1)) {
                rprintf(FWARNING, "renaming %s to %s because of text busy\n",
                        fname, path);
        }
@@ -1019,7 +1018,7 @@ int change_dir(const char *dir, int set_path_only)
                curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
        }
 
-       if (verbose >= 5 && !set_path_only)
+       if (DEBUG_GTE(CHDIR, 1) && !set_path_only)
                rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);
 
        return 1;
@@ -1583,7 +1582,7 @@ void *expand_item_list(item_list *lp, size_t item_size,
                        overflow_exit("expand_item_list");
                /* Using _realloc_array() lets us pass the size, not a type. */
                new_ptr = _realloc_array(lp->items, item_size, new_size);
-               if (verbose >= 4) {
+               if (DEBUG_GTE(FLIST, 3)) {
                        rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",
                                who_am_i(), desc, (double)new_size * item_size,
                                new_ptr == lp->items ? " not" : "");