mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-10-21 05:14:15 -04:00
Add the --stop-after & --stop-at options.
This commit is contained in:
1 parent
d495e343c0
commit
af531cf787
5 files changed
+234
-3
No files matched your search
@@ -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:
|
||||
|
||||
+1
-1
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
+41
@@ -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
|
||||
|
||||
Reference in new issue
Block a user