This mode is useful when a process is monitoring the log for
post-processing of transferred files.

With --log-after in local mode, both sender and receiver log to
the same log file, so it require --log-file with absolute path.

We add %o to the default log format, so it will be easy to tell
the logs of the sender from the logs of the receiver:

2023/02/14 14:40:25 [559755] building file list
2023/02/14 14:40:25 [559755] send >f+++++++++ foo
2023/02/14 14:40:25 [559757] recv >f+++++++++ foo
2023/02/14 14:40:25 [559755] sent 111 bytes  received 35 bytes  292.00 bytes/sec
2023/02/14 14:40:25 [559755] total size is 4  speedup is 0.03
---

Hi Wayne,

This is my first time contributing to rsync.

I've sent this also as a pull request a while back:
https://github.com/WayneD/rsync/pull/442

I have more pending contributions after this small one goes through,
mainly around performance and functionality of syncing files between
cifs mounts, which is the main use case of my employer.

I am not sure if rsync development follows some release cycle of
features vs. bug fixes and did not find any documentation regarding the
preferred way of posting features, so trying a patch now is case this is
preferred over github PR.

Let me know if there is anything else that is required.

Thanks,
Amir.

 log.c      |  9 +++++++++
 main.c     |  7 +++++++
 options.c  | 20 +++++++++++++++++++-
 receiver.c |  9 ++++++++-
 rsync.1.md |  1 +
 rsync.h    |  3 ++-
 6 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/log.c b/log.c
index e4ba1cce..a973b519 100644
--- a/log.c
+++ b/log.c
@@ -47,6 +47,7 @@ extern mode_t orig_umask;
 extern char *auth_user;
 extern char *stdout_format;
 extern char *logfile_format;
+extern char *logafter_format;
 extern char *logfile_name;
 #ifdef ICONV_CONST
 extern iconv_t ic_chck;
@@ -271,6 +272,8 @@ void rwrite(enum logcode code, const char *buf, int len, 
int is_utf8)
                 * that the msg gets logged and then sent to stderr after that. 
*/
                if (am_daemon > 0 && code != FCLIENT)
                        code = FLOG;
+       } else if (code == FLOG_AFTER) {
+               code = FLOG;
        } else if (send_msgs_to_gen) {
                assert(!is_utf8);
                /* Pass the message to our sibling in native charset. */
@@ -813,6 +816,12 @@ void log_item(enum logcode code, struct file_struct *file, 
int iflags, const cha
 {
        const char *s_or_r = am_sender ? "send" : "recv";
 
+       if (code == FLOG_AFTER) {
+               if (logafter_format && *logafter_format)
+                       log_formatted(FLOG_AFTER, logafter_format, s_or_r, 
file, NULL, iflags, hlink);
+               return;
+       }
+
        if (code != FLOG && stdout_format && !am_server)
                log_formatted(FCLIENT, stdout_format, s_or_r, file, NULL, 
iflags, hlink);
        if (code != FCLIENT && logfile_format && *logfile_format)
diff --git a/main.c b/main.c
index 0c60b86d..adc14965 100644
--- a/main.c
+++ b/main.c
@@ -93,7 +93,10 @@ extern int trust_sender_filter;
 extern int trust_sender_args;
 extern struct stats stats;
 extern char *stdout_format;
+extern char *logfile_name;
 extern char *logfile_format;
+extern char *logafter_name;
+extern int log_after_transfer;
 extern char *filesfrom_host;
 extern char *partial_dir;
 extern char *rsync_path;
@@ -1053,6 +1056,10 @@ static int do_recv(int f_in, int f_out, char *local_name)
                        io_start_buffering_in(f_in);
                io_start_multiplex_out(f_out);
 
+               /* Reopen log file for --log-after */
+               if (log_after_transfer)
+                       logfile_name = logafter_name;
+
                recv_files(f_in, f_out, local_name);
                io_flush(FULL_FLUSH);
                handle_stats(f_in);
diff --git a/options.c b/options.c
index fd674754..4ab83650 100644
--- a/options.c
+++ b/options.c
@@ -176,7 +176,9 @@ char *basis_dir[MAX_BASIS_DIRS+1];
 char *config_file = NULL;
 char *shell_cmd = NULL;
 char *logfile_name = NULL;
+char *logafter_name = NULL;
 char *logfile_format = NULL;
+char *logafter_format = NULL;
 char *stdout_format = NULL;
 char *password_file = NULL;
 char *early_input_file = NULL;
@@ -205,6 +207,7 @@ static const char *empty_argv[1];
 int quiet = 0;
 int output_motd = 1;
 int log_before_transfer = 0;
+int log_after_transfer = 0;
 int stdout_format_has_i = 0;
 int stdout_format_has_o_or_i = 0;
 int logfile_format_has_i = 0;
@@ -769,6 +772,7 @@ static struct poptOption long_options[] = {
   {"no-m",             0,  POPT_ARG_VAL,    &prune_empty_dirs, 0, 0, 0 },
   {"log-file",         0,  POPT_ARG_STRING, &logfile_name, 0, 0, 0 },
   {"log-file-format",  0,  POPT_ARG_STRING, &logfile_format, 0, 0, 0 },
+  {"log-after",        0,  POPT_ARG_VAL,    &log_after_transfer, 1, 0, 0 },
   {"out-format",       0,  POPT_ARG_STRING, &stdout_format, 0, 0, 0 },
   {"log-format",       0,  POPT_ARG_STRING, &stdout_format, 0, 0, 0 }, /* 
DEPRECATED */
   {"itemize-changes", 'i', POPT_ARG_NONE,   0, 'i', 0, 0 },
@@ -2359,7 +2363,10 @@ int parse_arguments(int *argc_p, const char ***argv_p)
 
        if (logfile_name && !am_daemon) {
                if (!logfile_format) {
-                       logfile_format = "%i %n%L";
+                       if (log_after_transfer)
+                               logfile_format = "%o %i %n%L";
+                       else
+                               logfile_format = "%i %n%L";
                        logfile_format_has_i = logfile_format_has_o_or_i = 1;
                } else {
                        if (log_format_has(logfile_format, 'i'))
@@ -2371,6 +2378,17 @@ int parse_arguments(int *argc_p, const char ***argv_p)
        } else if (!am_daemon)
                logfile_format = NULL;
 
+       if (log_after_transfer) {
+               if (!logfile_name || *logfile_name != '/') {
+                       snprintf(err_buf, sizeof err_buf,
+                                "--log-after requires --log-file=<absolute 
path>\n");
+                       goto cleanup;
+               }
+               log_before_transfer = 0;
+               logafter_name = logfile_name;
+               logafter_format = logfile_format;
+       }
+
        if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit))
                bwlimit = daemon_bwlimit;
        if (bwlimit) {
diff --git a/receiver.c b/receiver.c
index 6b4b369e..c200ef28 100644
--- a/receiver.c
+++ b/receiver.c
@@ -28,6 +28,7 @@ extern int am_root;
 extern int am_server;
 extern int inc_recurse;
 extern int log_before_transfer;
+extern int log_after_transfer;
 extern int stdout_format_has_i;
 extern int logfile_format_has_i;
 extern int want_xattr_optim;
@@ -876,7 +877,9 @@ int recv_files(int f_in, int f_out, char *local_name)
                /* recv file data */
                recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, 
fd2, file, inplace || one_inplace);
 
-               log_item(log_code, file, iflags, NULL);
+               /* log the transfer result after file is moved into place */
+               if (!log_after_transfer)
+                       log_item(log_code, file, iflags, NULL);
                if (want_progress_now)
                        instant_progress(fname);
 
@@ -917,6 +920,10 @@ int recv_files(int f_in, int f_out, char *local_name)
                } else if (!one_inplace)
                        do_unlink(fnametmp);
 
+               /* log the transfer result */
+               if (log_after_transfer)
+                       log_item(FLOG_AFTER, file, iflags, NULL);
+
                cleanup_disable();
 
                if (read_batch)
diff --git a/rsync.1.md b/rsync.1.md
index 2ae6f481..1991e406 100644
--- a/rsync.1.md
+++ b/rsync.1.md
@@ -543,6 +543,7 @@ has its own detailed description later in this manpage.
 --out-format=FORMAT      output updates using the specified FORMAT
 --log-file=FILE          log what we're doing to the specified FILE
 --log-file-format=FMT    log updates using the specified FMT
+--log-after              log updates after moving file into place
 --password-file=FILE     read daemon-access password from FILE
 --early-input=FILE       use FILE for daemon's early exec input
 --list-only              list the files instead of copying them
diff --git a/rsync.h b/rsync.h
index d3709fe0..92d22f61 100644
--- a/rsync.h
+++ b/rsync.h
@@ -253,8 +253,9 @@ enum logcode {
     FERROR_XFER=1, FINFO=2, /* sent over socket for any protocol */
     FERROR=3, FWARNING=4, /* sent over socket for protocols >= 30 */
     FERROR_SOCKET=5, FLOG=6, /* only sent via receiver -> generator pipe */
+    FCLIENT=7,     /* never transmitted (e.g. server converts to FINFO) */
     FERROR_UTF8=8, /* only sent via receiver -> generator pipe */
-    FCLIENT=7 /* never transmitted (e.g. server converts to FINFO) */
+    FLOG_AFTER=9,  /* receiver logs directly to log file */
 };
 
 /* Messages types that are sent over the message channel.  The logcode
-- 
2.34.1


-- 
Please use reply-all for most replies to avoid omitting the mailing list.
To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync
Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html

Reply via email to