[SCM] The rsync repository. - branch master updated

Rsync CVS commit messages rsync-cvs at lists.samba.org
Mon Jul 13 01:34:07 UTC 2020


The branch, master has been updated
       via  af531cf7 Add the --stop-after & --stop-at options.
      from  d495e343 A few word tweaks.

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


- Log -----------------------------------------------------------------
commit af531cf787995f6a3bc381cd1da1988192e7ef59
Author: Wayne Davison <wayne at opencoder.net>
Date:   Sun Jul 12 18:32:41 2020 -0700

    Add the --stop-after & --stop-at options.

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

Summary of changes:
 NEWS.md      |   4 ++
 configure.ac |   2 +-
 io.c         |   9 ++-
 options.c    | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 rsync.1.md   |  41 ++++++++++++++
 5 files changed, 234 insertions(+), 3 deletions(-)


Changeset truncated at 500 lines:

diff --git a/NEWS.md b/NEWS.md
index 9bd98bae..30a74128 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -21,6 +21,10 @@
    other user/group names in the transfer (instead of assuming that both sides
    have the same id-0 names).
 
+ - Added the `--stop-after=MINS` and `--stop-at=DATE_TIME` options (with the
+   `--time-limit=MINS` option accepted as an alias for `--stop-after`).  This
+   is an enhanced version of the time-limit patch from the patches repo.
+
  - Added some compatibility code for HPE NonStop platforms.
 
 ### INTERNAL:
diff --git a/configure.ac b/configure.ac
index 69c8f933..fac166c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -822,7 +822,7 @@ AC_FUNC_UTIME_NULL
 AC_FUNC_ALLOCA
 AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \
     fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
-    chflags getattrlist \
+    chflags getattrlist mktime \
     memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
     strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
     setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
diff --git a/io.c b/io.c
index ddd20fa8..1785f832 100644
--- a/io.c
+++ b/io.c
@@ -60,6 +60,7 @@ extern int preserve_hard_links;
 extern BOOL extra_flist_sending_enabled;
 extern BOOL flush_ok_after_signal;
 extern struct stats stats;
+extern time_t stop_at_utime;
 extern struct file_list *cur_flist;
 #ifdef ICONV_OPTION
 extern int filesfrom_convert;
@@ -785,9 +786,13 @@ static char *perform_io(size_t needed, int flags)
 			if (msgs2stderr && DEBUG_GTE(IO, 2))
 				rprintf(FINFO, "[%s] recv=%ld\n", who_am_i(), (long)n);
 
-			if (io_timeout) {
+			if (io_timeout || stop_at_utime) {
 				last_io_in = time(NULL);
-				if (flags & PIO_NEED_INPUT)
+				if (stop_at_utime && last_io_in >= stop_at_utime) {
+					rprintf(FERROR, "stopping at requested limit\n");
+					exit_cleanup(RERR_TIMEOUT);
+				}
+				if (io_timeout && flags & PIO_NEED_INPUT)
 					maybe_send_keepalive(last_io_in, 0);
 			}
 			stats.total_read += n;
diff --git a/options.c b/options.c
index 1e438fb1..9ed16405 100644
--- a/options.c
+++ b/options.c
@@ -119,6 +119,7 @@ size_t bwlimit_writemax = 0;
 int ignore_existing = 0;
 int ignore_non_existing = 0;
 int need_messages_from_generator = 0;
+time_t stop_at_utime = 0;
 int max_delete = INT_MIN;
 OFF_T max_size = -1;
 OFF_T min_size = -1;
@@ -664,6 +665,11 @@ static void print_info_flags(enum logcode f)
 #endif
 			"prealloc",
 
+#ifndef HAVE_MKTIME
+		"no "
+#endif
+			"stop-at",
+
 	"*Optimizations",
 
 #ifndef HAVE_SIMD
@@ -779,6 +785,7 @@ enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
       OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_BLOCK_SIZE,
       OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT,
       OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS,
+      OPT_STOP_AFTER, OPT_STOP_AT,
       OPT_REFUSED_BASE = 9000};
 
 static struct poptOption long_options[] = {
@@ -988,6 +995,9 @@ static struct poptOption long_options[] = {
   {"no-timeout",       0,  POPT_ARG_VAL,    &io_timeout, 0, 0, 0 },
   {"contimeout",       0,  POPT_ARG_INT,    &connect_timeout, 0, 0, 0 },
   {"no-contimeout",    0,  POPT_ARG_VAL,    &connect_timeout, 0, 0, 0 },
+  {"stop-after",       0,  POPT_ARG_STRING, 0, OPT_STOP_AFTER, 0, 0 },
+  {"time-limit",       0,  POPT_ARG_STRING, 0, OPT_STOP_AFTER, 0, 0 }, /* earlier stop-after name */
+  {"stop-at",          0,  POPT_ARG_STRING, 0, OPT_STOP_AT, 0, 0 },
   {"rsh",             'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
   {"rsync-path",       0,  POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
@@ -1192,6 +1202,9 @@ static void set_refuse_options(void)
 #ifndef SUPPORT_HARD_LINKS
 	parse_one_refuse_match(0, "link-dest", list_end);
 #endif
+#ifndef HAVE_MKTIME
+	parse_one_refuse_match(0, "stop-at", list_end);
+#endif
 #ifndef ICONV_OPTION
 	parse_one_refuse_match(0, "iconv", list_end);
 #endif
@@ -1326,6 +1339,148 @@ failure:
 	return -1;
 }
 
+#ifdef HAVE_MKTIME
+/* Allow the user to specify a time in the format yyyy-mm-ddThh:mm while
+ * also allowing abbreviated data.  For instance, if the time is omitted,
+ * it defaults to midnight.  If the date is omitted, it defaults to the
+ * next possible date in the future with the specified time.  Even the
+ * year or year-month can be omitted, again defaulting to the next date
+ * in the future that matches the specified information.  A 2-digit year
+ * is also OK, as is using '/' instead of '-'. */
+static time_t parse_time(const char *arg)
+{
+	const char *cp;
+	time_t val, now = time(NULL);
+	struct tm t, *today = localtime(&now);
+	int in_date, old_mday, n;
+
+	memset(&t, 0, sizeof t);
+	t.tm_year = t.tm_mon = t.tm_mday = -1;
+	t.tm_hour = t.tm_min = t.tm_isdst = -1;
+	cp = arg;
+	if (*cp == 'T' || *cp == 't' || *cp == ':') {
+		in_date = *cp == ':' ? 0 : -1;
+		cp++;
+	} else
+		in_date = 1;
+	for ( ; ; cp++) {
+		if (!isDigit(cp))
+			return (time_t)-1;
+		n = 0;
+		do {
+			n = n * 10 + *cp++ - '0';
+		} while (isDigit(cp));
+		if (*cp == ':')
+			in_date = 0;
+		if (in_date > 0) {
+			if (t.tm_year != -1)
+				return (time_t)-1;
+			t.tm_year = t.tm_mon;
+			t.tm_mon = t.tm_mday;
+			t.tm_mday = n;
+			if (!*cp)
+				break;
+			if (*cp == 'T' || *cp == 't') {
+				if (!cp[1])
+					break;
+				in_date = -1;
+			} else if (*cp != '-' && *cp != '/')
+				return (time_t)-1;
+			continue;
+		}
+		if (t.tm_hour != -1)
+			return (time_t)-1;
+		t.tm_hour = t.tm_min;
+		t.tm_min = n;
+		if (!*cp) {
+			if (in_date < 0)
+				return (time_t)-1;
+			break;
+		}
+		if (*cp != ':')
+			return (time_t)-1;
+		in_date = 0;
+	}
+
+	in_date = 0;
+	if (t.tm_year < 0) {
+		t.tm_year = today->tm_year;
+		in_date = 1;
+	} else if (t.tm_year < 100) {
+		while (t.tm_year < today->tm_year)
+			t.tm_year += 100;
+	} else
+		t.tm_year -= 1900;
+	if (t.tm_mon < 0) {
+		t.tm_mon = today->tm_mon;
+		in_date = 2;
+	} else
+		t.tm_mon--;
+	if (t.tm_mday < 0) {
+		t.tm_mday = today->tm_mday;
+		in_date = 3;
+	}
+
+	n = 0;
+	if (t.tm_min < 0) {
+		t.tm_hour = t.tm_min = 0;
+	} else if (t.tm_hour < 0) {
+		if (in_date != 3)
+			return (time_t)-1;
+		in_date = 0;
+		t.tm_hour = today->tm_hour;
+		n = 60*60;
+	}
+
+	/* Note that mktime() might change a too-large tm_mday into the start of
+	 * the following month which we need to undo in the following code! */
+	old_mday = t.tm_mday;
+	if (t.tm_hour > 23 || t.tm_min > 59
+	    || t.tm_mon < 0 || t.tm_mon >= 12
+	    || t.tm_mday < 1 || t.tm_mday > 31
+	    || (val = mktime(&t)) == (time_t)-1)
+		return (time_t)-1;
+
+	while (in_date && (val <= now || t.tm_mday < old_mday)) {
+		switch (in_date) {
+		case 3:
+			old_mday = ++t.tm_mday;
+			break;
+		case 2:
+			if (t.tm_mday < old_mday)
+				t.tm_mday = old_mday; /* The month already got bumped forward */
+			else if (++t.tm_mon == 12) {
+				t.tm_mon = 0;
+				t.tm_year++;
+			}
+			break;
+		case 1:
+			if (t.tm_mday < old_mday) {
+				/* mon==1 mday==29 got bumped to mon==2 */
+				if (t.tm_mon != 2 || old_mday != 29)
+					return (time_t)-1;
+				t.tm_mon = 1;
+				t.tm_mday = 29;
+			}
+			t.tm_year++;
+			break;
+		}
+		if ((val = mktime(&t)) == (time_t)-1) {
+			/* This code shouldn't be needed, as mktime() should auto-round to the next month. */
+			if (in_date != 3 || t.tm_mday <= 28)
+				return (time_t)-1;
+			t.tm_mday = old_mday = 1;
+			in_date = 2;
+		}
+	}
+	if (n) {
+		while (val <= now)
+			val += n;
+	}
+	return val;
+}
+#endif
+
 static void create_refuse_error(int which)
 {
 	const char *msg;
@@ -1892,6 +2047,32 @@ int parse_arguments(int *argc_p, const char ***argv_p)
 			return 0;
 #endif
 
+		case OPT_STOP_AFTER: {
+			long val;
+			arg = poptGetOptArg(pc);
+			stop_at_utime = time(NULL);
+			if ((val = atol(arg) * 60) <= 0 || val + (long)stop_at_utime < 0) {
+				snprintf(err_buf, sizeof err_buf, "invalid --stop-after value: %s\n", arg);
+				return 0;
+			}
+			stop_at_utime += val;
+			break;
+		}
+
+#ifdef HAVE_MKTIME
+		case OPT_STOP_AT:
+			arg = poptGetOptArg(pc);
+			if ((stop_at_utime = parse_time(arg)) == (time_t)-1) {
+				snprintf(err_buf, sizeof err_buf, "invalid --stop-at format: %s\n", arg);
+				return 0;
+			}
+			if (stop_at_utime <= time(NULL)) {
+				snprintf(err_buf, sizeof err_buf, "--stop-at time is not in the future: %s\n", arg);
+				return 0;
+			}
+			break;
+#endif
+
 		default:
 			/* A large opt value means that set_refuse_options()
 			 * turned this option off. */
diff --git a/rsync.1.md b/rsync.1.md
index 685c5c37..5be8029c 100644
--- a/rsync.1.md
+++ b/rsync.1.md
@@ -457,6 +457,8 @@ detailed description below for a complete description.
 --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
+--stop-after=MINS        Stop rsync after MINS minutes have elapsed
+--stop-at=y-m-dTh:m      Stop rsync at the specified moment in time
 --write-batch=FILE       write a batched update to FILE
 --only-write-batch=FILE  like --write-batch but w/o updating dest
 --read-batch=FILE        read a batched update from FILE
@@ -3113,6 +3115,45 @@ your home directory (remove the '=' for that).
     buffered, while other can show up as very slow when the flushing of the
     output buffer occurs.  This may be fixed in a future version.
 
+0.  `--stop-after=MINS
+
+    This option tells rsync to stop copying when the specified number of
+    minutes has elapsed.
+
+    Rsync also accepts an earlier version of this option: `--time-limit=MINS`.
+
+    For maximal flexibility, rsync does not communicate this option to the
+    remote rsync since it is usually enough that one side of the connection
+    quits as specified.  This allows the option's use even when only one side
+    of the connection supports it.  You can tell the remote side about the time
+    limit using `--remote-option` (`-M`), should the need arise.
+
+0.  `--stop-at=y-m-dTh:m
+
+    This option tells rsync to stop copying when the specified point in time
+    has been reached. The date & time can be fully specified in a numeric
+    format of year-month-dayThour:minute (e.g. 2000-12-31T23:59) in the local
+    timezone.  You may choose to separate the date numbers using slashes
+    instead of dashes.
+
+    The value can also be abbreviated in a variety of ways, such as specifying
+    a 2-digit year and/or leaving off various values.  In all cases, the value
+    will be taken to be the next possible future moment where the supplied
+    information matches.  If the value specifies the current time or a past
+    time, rsync exits with an error.
+
+    For example, "1-30" specifies the next January 30th (at midnight local
+    time), "14:00" specifies the next 2 P.M., "1" specifies the next 1st of the
+    month at midnight, and ":59" specifies the next 59th minute after the hour.
+
+    For maximal flexibility, rsync does not communicate this option to the
+    remote rsync since it is usually enough that one side of the connection
+    quits as specified.  This allows the option's use even when only one side
+    of the connection supports it.  You can tell the remote side about the time
+    limit using `--remote-option` (`-M`), should the need arise.  Do keep in
+    mind that the remote host may have a different default timezone than your
+    local host.
+
 0.  `--write-batch=FILE`
 
     Record a file that can later be applied to another identical destination


-- 
The rsync repository.



More information about the rsync-cvs mailing list