[SCM] The rsync repository. - branch master updated

Rsync CVS commit messages rsync-cvs at lists.samba.org
Sun Jun 21 21:32:27 UTC 2020


The branch, master has been updated
       via  e16b2275 Add `--early-input=FILE` option.
      from  7587e20c Output a helpful msg about configure only if the command fails.

https://git.samba.org/?p=rsync.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit e16b22751a7996ddba299ea0750b533ce492d12f
Author: Wayne Davison <wayne at opencoder.net>
Date:   Sun Jun 21 14:32:00 2020 -0700

    Add `--early-input=FILE` option.

-----------------------------------------------------------------------

Summary of changes:
 NEWS.md        |   3 ++
 clientserver.c | 126 +++++++++++++++++++++++++++++++++++++++++----------------
 options.c      |   2 +
 rsync.1.md     |  10 +++++
 4 files changed, 106 insertions(+), 35 deletions(-)


Changeset truncated at 500 lines:

diff --git a/NEWS.md b/NEWS.md
index 8b3e2ed0..4ff2a446 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -23,6 +23,9 @@ Protocol: 31 (unchanged)
 
 ### ENHANCEMENTS:
 
+ - Added `--early-input=FILE` option that allows the client to send some
+   data to the "early exec" daemon script on its stdin.
+
  - Added "atimes" to the capabilities list that `--version` outputs.
 
  - Mention either "default protect-args" or "optional protect-args" in the
diff --git a/clientserver.c b/clientserver.c
index 819e9f24..4d7ba1f0 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -54,6 +54,7 @@ extern char *config_file;
 extern char *logfile_format;
 extern char *files_from;
 extern char *tmpdir;
+extern char *early_input_file;
 extern struct chmod_mode_struct *chmod_modes;
 extern filter_rule_list daemon_filter_list;
 #ifdef ICONV_OPTION
@@ -67,8 +68,13 @@ char *auth_user;
 int read_only = 0;
 int module_id = -1;
 int pid_file_fd = -1;
+int early_input_len = 0;
+char *early_input = NULL;
 struct chmod_mode_struct *daemon_chmod_modes;
 
+#define EARLY_INPUT_CMD "#early_input="
+#define EARLY_INPUT_CMDLEN (sizeof EARLY_INPUT_CMD - 1)
+
 /* module_dirlen is the length of the module_dir string when in daemon
  * mode and module_dir is not "/"; otherwise 0.  (Note that a chroot-
  * enabled module can have a non-"/" module_dir these days.) */
@@ -144,14 +150,12 @@ static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int
 #else
 	int our_sub = 0;
 #endif
-	char *motd;
 
 	io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub);
-
 	if (!am_client) {
-		motd = lp_motd_file();
+		char *motd = lp_motd_file();
 		if (motd && *motd) {
-			FILE *f = fopen(motd,"r");
+			FILE *f = fopen(motd, "r");
 			while (f && !feof(f)) {
 				int len = fread(buf, 1, bufsiz - 1, f);
 				if (len > 0)
@@ -245,6 +249,36 @@ int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char
 	if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0)
 		return -1;
 
+	if (early_input_file) {
+		STRUCT_STAT st;
+		FILE *f = fopen(early_input_file, "rb");
+		if (!f || do_fstat(fileno(f), &st) < 0) {
+			rsyserr(FERROR, errno, "failed to open %s", early_input_file);
+			return -1;
+		}
+		early_input_len = st.st_size;
+		if (early_input_len >= (int)sizeof line) {
+			rprintf(FERROR, "%s is >= %d bytes.\n", early_input_file, (int)sizeof line);
+			return -1;
+		}
+		if (early_input_len > 0) {
+			io_printf(f_out, EARLY_INPUT_CMD "%d\n", early_input_len);
+			while (early_input_len > 0) {
+				int len;
+				if (feof(f)) {
+					rprintf(FERROR, "Early EOF in %s\n", early_input_file);
+					return -1;
+				}
+				len = fread(line, 1, early_input_len / 2 + 1, f);
+				if (len > 0) {
+					write_buf(f_out, line, len);
+					early_input_len -= len;
+				}
+			}
+		}
+		fclose(f);
+	}
+
 	/* set daemon_over_rsh to false since we need to build the
 	 * true set of args passed through the rsh/ssh connection;
 	 * this is a no-op for direct-socket-connection mode */
@@ -397,7 +431,7 @@ static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
 	int arg_fds[2], error_fds[2], arg_fd;
 	pid_t pid;
 
-	if ((error_fd_ptr && pipe(error_fds) < 0) || (arg_fd_ptr && pipe(arg_fds) < 0) || (pid = fork()) < 0)
+	if ((error_fd_ptr && pipe(error_fds) < 0) || pipe(arg_fds) < 0 || (pid = fork()) < 0)
 		return (pid_t)-1;
 
 	if (pid == 0) {
@@ -409,37 +443,35 @@ static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
 			set_blocking(error_fds[1]);
 		}
 
-		if (arg_fd_ptr) {
-			close(arg_fds[1]);
-			arg_fd = arg_fds[0];
-			set_blocking(arg_fd);
+		close(arg_fds[1]);
+		arg_fd = arg_fds[0];
+		set_blocking(arg_fd);
+
+		len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
+		if (len <= 0)
+			_exit(1);
+		set_env_str("RSYNC_REQUEST", buf);
 
+		for (j = 0; ; j++) {
+			char *p;
 			len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
-			if (len <= 0)
+			if (len <= 0) {
+				if (!len)
+					break;
 				_exit(1);
-			set_env_str("RSYNC_REQUEST", buf);
-
-			for (j = 0; ; j++) {
-				char *p;
-				len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN);
-				if (len <= 0) {
-					if (!len)
-						break;
-					_exit(1);
-				}
-				if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0)
-					putenv(p);
 			}
-			close(arg_fd);
+			if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0)
+				putenv(p);
 		}
 
+		dup2(arg_fd, STDIN_FILENO);
+		close(arg_fd);
+
 		if (error_fd_ptr) {
 			dup2(error_fds[1], STDOUT_FILENO);
 			close(error_fds[1]);
 		}
 
-		close(STDIN_FILENO);
-
 		status = shell_exec(cmd);
 
 		if (!WIFEXITED(status))
@@ -453,16 +485,14 @@ static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr)
 		set_blocking(error_fds[0]);
 	}
 
-	if (arg_fd_ptr) {
-		close(arg_fds[0]);
-		arg_fd = *arg_fd_ptr = arg_fds[1];
-		set_blocking(arg_fd);
-	}
+	close(arg_fds[0]);
+	arg_fd = *arg_fd_ptr = arg_fds[1];
+	set_blocking(arg_fd);
 
 	return pid;
 }
 
-static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv)
+static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv, int am_early)
 {
 	int j = 0;
 
@@ -475,10 +505,15 @@ static void write_pre_exec_args(int write_fd, char *request, char **early_argv,
 			write_buf(write_fd, *early_argv, strlen(*early_argv)+1);
 		j = 1; /* Skip arg0 name in argv. */
 	}
-	for ( ; argv[j]; j++)
-		write_buf(write_fd, argv[j], strlen(argv[j])+1);
+	if (argv) {
+		for ( ; argv[j]; j++)
+			write_buf(write_fd, argv[j], strlen(argv[j])+1);
+	}
 	write_byte(write_fd, 0);
 
+	if (am_early && early_input_len)
+		write_buf(write_fd, early_input, early_input_len);
+
 	close(write_fd);
 }
 
@@ -812,12 +847,14 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 		/* For early exec, fork a child process to run the indicated
 		 * command and wait for it to exit. */
 		if (*lp_early_exec(i)) {
-			pid_t pid = start_pre_exec(lp_early_exec(i), NULL, NULL);
+			int arg_fd;
+			pid_t pid = start_pre_exec(lp_early_exec(i), &arg_fd, NULL);
 			if (pid == (pid_t)-1) {
 				rsyserr(FLOG, errno, "early exec preparation failed");
 				io_printf(f_out, "@ERROR: early exec preparation failed\n");
 				return -1;
 			}
+			write_pre_exec_args(arg_fd, NULL, NULL, NULL, 1);
 			if (finish_pre_exec("early exec", pid, -1) != NULL) {
 				rsyserr(FLOG, errno, "early exec failed");
 				io_printf(f_out, "@ERROR: early exec failed\n");
@@ -839,6 +876,11 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 	}
 #endif
 
+	if (early_input) {
+		free(early_input);
+		early_input = NULL;
+	}
+
 	if (use_chroot) {
 		/*
 		 * XXX: The 'use chroot' flag is a fairly reliable
@@ -953,7 +995,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
 		msgs2stderr = 0; /* A non-rsh-run daemon doesn't have stderr for msgs. */
 
 	if (pre_exec_pid) {
-		write_pre_exec_args(pre_exec_arg_fd, request, orig_early_argv, orig_argv);
+		write_pre_exec_args(pre_exec_arg_fd, request, orig_early_argv, orig_argv, 0);
 		err_msg = finish_pre_exec("pre-xfer exec", pre_exec_pid, pre_exec_error_fd);
 	}
 
@@ -1185,6 +1227,20 @@ int start_daemon(int f_in, int f_out)
 	if (!read_line_old(f_in, line, sizeof line, 0))
 		return -1;
 
+	if (strncmp(line, EARLY_INPUT_CMD, EARLY_INPUT_CMDLEN) == 0) {
+		early_input_len = strtol(line + EARLY_INPUT_CMDLEN, NULL, 10);
+		if (early_input_len <= 0 || early_input_len >= BIGPATHBUFLEN) {
+			io_printf(f_out, "@ERROR: invalid early_input length\n");
+			return -1;
+		}
+		if (!(early_input = new_array(char, early_input_len)))
+			out_of_memory("exchange_protocols");
+		read_buf(f_in, early_input, early_input_len);
+
+		if (!read_line_old(f_in, line, sizeof line, 0))
+			return -1;
+	}
+
 	if (!*line || strcmp(line, "#list") == 0) {
 		rprintf(FLOG, "module-list request from %s (%s)\n",
 			host, addr);
diff --git a/options.c b/options.c
index 6c99dd4b..c68b43b9 100644
--- a/options.c
+++ b/options.c
@@ -170,6 +170,7 @@ char *logfile_name = NULL;
 char *logfile_format = NULL;
 char *stdout_format = NULL;
 char *password_file = NULL;
+char *early_input_file = NULL;
 char *rsync_path = RSYNC_PATH;
 char *backup_dir = NULL;
 char backup_dir_buf[MAXPATHLEN];
@@ -996,6 +997,7 @@ static struct poptOption long_options[] = {
   {"port",             0,  POPT_ARG_INT,    &rsync_port, 0, 0, 0 },
   {"sockopts",         0,  POPT_ARG_STRING, &sockopts, 0, 0, 0 },
   {"password-file",    0,  POPT_ARG_STRING, &password_file, 0, 0, 0 },
+  {"early-input",      0,  POPT_ARG_STRING, &early_input_file, 0, 0, 0 },
   {"blocking-io",      0,  POPT_ARG_VAL,    &blocking_io, 1, 0, 0 },
   {"no-blocking-io",   0,  POPT_ARG_VAL,    &blocking_io, 0, 0, 0 },
   {"outbuf",           0,  POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 },
diff --git a/rsync.1.md b/rsync.1.md
index 137c25a5..4a3099b9 100644
--- a/rsync.1.md
+++ b/rsync.1.md
@@ -452,6 +452,7 @@ detailed description below for a complete description.
 --log-file=FILE          log what we're doing to the specified FILE
 --log-file-format=FMT    log updates using the specified FMT
 --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
 --bwlimit=RATE           limit socket I/O bandwidth
 --write-batch=FILE       write a batched update to FILE
@@ -2977,6 +2978,15 @@ your home directory (remove the '=' for that).
     authentication (i.e. if you have also specified a password in the daemon's
     config file).
 
+0. `--early-input=FILE`
+
+    This option allows rsync to send up to 5K of data to the "early exec"
+    script on its stdin.  One possible use of this data is to give the script a
+    secret that can be used to mount an encrypted filesystem (which you should
+    unmount in the the "post-xfer exec" script).
+
+    The daemon must be at least version 3.2.1.
+
 0. `--list-only`
 
     This option will cause the source files to be listed instead of


-- 
The rsync repository.



More information about the rsync-cvs mailing list