[PATCH] Add option --log-after to log after moving file into place
Amir Goldstein
amir73il at gmail.com
Mon Jul 3 06:05:22 UTC 2023
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
More information about the rsync
mailing list