X-Git-Url: https://mattmccutchen.net/rsync/rsync-patches.git/blobdiff_plain/ea238f1cf5038ad498b55223edca4b981b3067a8..c1ff70aa47e11c5b37634479a0facee775a7b6d9:/time-limit.diff diff --git a/time-limit.diff b/time-limit.diff index 3e434b4..1ec9c19 100644 --- a/time-limit.diff +++ b/time-limit.diff @@ -1,102 +1,97 @@ John Taylor's patch for implementing --time-limit and --stop-at, reworked to be simpler and more efficient by Wayne Davison. -Do we need configure support for mktime() and strptime()? +Do we need configure support for mktime()? ---- io.c 8 May 2004 18:03:43 -0000 1.120 -+++ io.c 8 May 2004 18:42:14 -0000 -@@ -44,6 +44,7 @@ static int io_multiplexing_in; - static int multiplex_in_fd = -1; - static int multiplex_out_fd = -1; - static time_t last_io; +To use this patch, run these commands for a successful build: + + patch -p1 = stop_at_utime) { + rprintf(FERROR, "run-time limit exceeded\n"); + exit_cleanup(RERR_TIMEOUT); + } + - if (!last_io) { -- last_io = time(NULL); -+ last_io = t; - return; - } -- -- t = time(NULL); - - if (last_io && io_timeout && (t-last_io) >= io_timeout) { - if (!am_server && !am_daemon) { ---- options.c 6 May 2004 21:08:01 -0000 1.148 -+++ options.c 8 May 2004 18:42:14 -0000 -@@ -92,6 +92,7 @@ int modify_window = 0; - int blocking_io = -1; - int checksum_seed = 0; - unsigned int block_size = 0; ++ if (!io_timeout || am_receiver) ++ return; ++ + if (allow_keepalive && we_send_keepalive_messages) { + /* This may put data into iobuf.msg w/o flushing. */ + maybe_send_keepalive(t, False); +diff --git a/options.c b/options.c +--- a/options.c ++++ b/options.c +@@ -112,6 +112,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; - - - /** Network address family. **/ -@@ -288,6 +289,8 @@ void usage(enum logcode F) - rprintf(F," --log-format=FORMAT log file transfers using specified format\n"); - rprintf(F," --password-file=FILE get password from FILE\n"); - rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n"); -+ rprintf(F," --stop-at=YY-MM-DD@HH:MM Stop rsync at year-month-day@hour:minute\n"); -+ rprintf(F," --time-limit=TIME Stop rsync after TIME minutes have elapsed\n"); - rprintf(F," --write-batch=PREFIX write batch fileset starting with PREFIX\n"); - rprintf(F," --read-batch=PREFIX read batch fileset starting with PREFIX\n"); - #ifdef INET6 -@@ -305,7 +308,7 @@ void usage(enum logcode F) - enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, - OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST, - OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, -- OPT_READ_BATCH, OPT_WRITE_BATCH, -+ OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_STOP_AT, OPT_TIME_LIMIT, - OPT_REFUSED_BASE = 9000}; + int max_delete = INT_MIN; + OFF_T max_size = 0; + OFF_T min_size = 0; +@@ -776,6 +777,8 @@ void usage(enum logcode F) + rprintf(F," --password-file=FILE read daemon-access password from FILE\n"); + rprintf(F," --list-only list the files instead of copying them\n"); + rprintf(F," --bwlimit=RATE limit socket I/O bandwidth\n"); ++ rprintf(F," --stop-at=y-m-dTh:m Stop rsync at year-month-dayThour:minute\n"); ++ rprintf(F," --time-limit=MINS Stop rsync after MINS minutes have elapsed\n"); + rprintf(F," --write-batch=FILE write a batched update to FILE\n"); + rprintf(F," --only-write-batch=FILE like --write-batch but w/o updating destination\n"); + rprintf(F," --read-batch=FILE read a batched update from FILE\n"); +@@ -800,6 +803,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, + OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE, + OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, + OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, ++ OPT_STOP_AT, OPT_TIME_LIMIT, + OPT_SERVER, OPT_REFUSED_BASE = 9000}; static struct poptOption long_options[] = { -@@ -377,6 +380,8 @@ static struct poptOption long_options[] - {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 }, - {"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 }, - {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 }, +@@ -989,6 +993,8 @@ 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-at", 0, POPT_ARG_STRING, 0, OPT_STOP_AT, 0, 0 }, + {"time-limit", 0, POPT_ARG_STRING, 0, OPT_TIME_LIMIT, 0, 0 }, - {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 }, - {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 }, - {"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 }, -@@ -471,6 +476,7 @@ int parse_arguments(int *argc, const cha - { - int opt; - char *ref = lp_refuse_options(module_id); -+ struct tm stop_at_tm; - const char *arg; - poptContext pc; - -@@ -584,6 +590,37 @@ int parse_arguments(int *argc, const cha + {"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 }, +@@ -1764,6 +1770,36 @@ int parse_arguments(int *argc_p, const char ***argv_p) return 0; #endif + case OPT_STOP_AT: + arg = poptGetOptArg(pc); -+ if (!strptime(arg, "%y-%m-%d@%H:%M", &stop_at_tm)) { ++ if ((stop_at_utime = parse_time(arg)) == (time_t)-1) { + snprintf(err_buf, sizeof err_buf, + "invalid --stop-at format: %s\n", + arg); + rprintf(FERROR, "ERROR: %s", err_buf); + return 0; + } -+ stop_at_utime = mktime(&stop_at_tm); + if (stop_at_utime < time(NULL)) { + snprintf(err_buf, sizeof err_buf, + "--stop-at time is in the past: %s\n", @@ -120,45 +115,189 @@ Do we need configure support for mktime() and strptime()? + default: /* A large opt value means that set_refuse_options() - * turned this option off (opt-BASE is its index). */ -@@ -881,6 +918,15 @@ void server_options(char **args,int *arg + * turned this option off. */ +@@ -2480,6 +2516,15 @@ void server_options(char **args, int *argc_p) + args[ac++] = arg; + } - if (bwlimit) { - if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0) -+ goto oom; -+ args[ac++] = arg; -+ } -+ + if (stop_at_utime) { + long mins = (stop_at_utime - time(NULL)) / 60; + if (mins <= 0) + mins = 1; + if (asprintf(&arg, "--time-limit=%ld", mins) < 0) - goto oom; - args[ac++] = arg; - } ---- rsync.yo 7 May 2004 00:18:37 -0000 1.169 -+++ rsync.yo 8 May 2004 18:42:15 -0000 -@@ -346,6 +346,8 @@ verb( - --log-format=FORMAT log file transfers using specified format - --password-file=FILE get password from FILE - --bwlimit=KBPS limit I/O bandwidth, KBytes per second -+ --stop-at=YY-MM-DD@HH:MM Stop rsync at year-month-day@hour:minute -+ --time-limit=TIME Stop rsync after TIME minutes have elapsed - --write-batch=PREFIX write batch fileset starting with PREFIX - --read-batch=PREFIX read batch fileset starting with PREFIX - -4 --ipv4 prefer IPv4 -@@ -890,6 +892,13 @@ of rsync transfers, blocks of data are s - transfer was too fast, it will wait before sending the next data block. The - result is an average transfer rate equaling the specified limit. A value - of zero specifies no limit. ++ goto oom; ++ args[ac++] = arg; ++ } + -+dit(bf(--stop-at=YY-MM-DD@HH:MM)) This option allows you to specify at what -+time to stop rsync, in year-month-day@hour:minute numeric format (e.g. -+04-12-3l@23:59). + if (backup_dir) { + args[ac++] = "--backup-dir"; + args[ac++] = backup_dir; +diff --git a/rsync.yo b/rsync.yo +--- a/rsync.yo ++++ b/rsync.yo +@@ -431,6 +431,8 @@ to the detailed description below for a complete description. verb( + --password-file=FILE read daemon-access password from FILE + --list-only list the files instead of copying them + --bwlimit=RATE limit socket I/O bandwidth ++ --stop-at=y-m-dTh:m Stop rsync at year-month-dayThour:minute ++ --time-limit=MINS Stop rsync after MINS minutes have elapsed + --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 +@@ -2309,6 +2311,19 @@ files can show up as being rapidly sent when the data is quickly 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. + ++dit(bf(--stop-at=y-m-dTh:m)) This option allows you to specify at what ++time to stop rsync, in year-month-dayThour:minute numeric format (e.g. ++2004-12-31T23:59). You can specify a 2 or 4-digit year. You can also ++leave off various items and the result will be the next possible time ++that matches the specified data. For example, "1-30" specifies the next ++January 30th (at midnight), "04:00" specifies the next 4am, "1" ++specifies the next 1st of the month at midnight, and ":59" specifies the ++next 59th minute after the hour. If you prefer, you may separate the ++date numbers using slashes instead of dashes. + -+dit(bf(--time-limit=TIME)) This option allows you to specify the maximum ++dit(bf(--time-limit=MINS)) This option allows you to specify the maximum +number of minutes rsync will run for. ++ + dit(bf(--write-batch=FILE)) Record a file that can later be applied to + another identical destination with bf(--read-batch). See the "BATCH MODE" + section for details, and also the bf(--only-write-batch) option. +diff --git a/util.c b/util.c +--- a/util.c ++++ b/util.c +@@ -123,6 +123,133 @@ NORETURN void overflow_exit(const char *str) + exit_cleanup(RERR_MALLOC); + } - dit(bf(--write-batch=PREFIX)) Generate a set of files that can be - transferred as a batch update. Each filename in the set starts with ++/* 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 '-'. */ ++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, 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 == ':') { ++ cp++; ++ in_date = 0; ++ } else ++ in_date = 1; ++ for ( ; ; cp++) { ++ if (!isDigit(cp)) ++ return -1; ++ ++ n = 0; ++ do { ++ n = n * 10 + *cp++ - '0'; ++ } while (isDigit(cp)); ++ ++ if (*cp == ':') ++ in_date = 0; ++ if (in_date) { ++ if (t.tm_year != -1) ++ return -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 = 0; ++ } else if (*cp != '-' && *cp != '/') ++ return -1; ++ continue; ++ } ++ if (t.tm_hour != -1) ++ return -1; ++ t.tm_hour = t.tm_min; ++ t.tm_min = n; ++ if (!*cp) ++ break; ++ if (*cp != ':') ++ return -1; ++ } ++ ++ 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 -1; ++ in_date = 0; ++ t.tm_hour = today->tm_hour; ++ n = 60*60; ++ } ++ ++ 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 -1; ++ ++ if (val <= now && in_date) { ++ tweak_date: ++ switch (in_date) { ++ case 3: ++ t.tm_mday++; ++ break; ++ case 2: ++ if (++t.tm_mon == 12) ++ t.tm_mon = 0; ++ else ++ break; ++ case 1: ++ t.tm_year++; ++ break; ++ } ++ if ((val = mktime(&t)) == (time_t)-1) { ++ if (in_date == 3 && t.tm_mday > 28) { ++ t.tm_mday = 1; ++ in_date = 2; ++ goto tweak_date; ++ } ++ return -1; ++ } ++ } ++ if (n) { ++ while (val <= now) ++ val += n; ++ } ++ return val; ++} ++ + int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) + { + #ifndef CAN_SET_SYMLINK_TIMES