X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3ac7f5d4c132301058ea0533468d6828f71cefcb..0c56b1add7d171499ae60c03b2eee3615f50e8ff:/options.c diff --git a/options.c b/options.c index 97e1daed..4fb9aa8b 100644 --- a/options.c +++ b/options.c @@ -84,12 +84,14 @@ int keep_partial = 0; int safe_symlinks = 0; int copy_unsafe_links = 0; int size_only = 0; +int daemon_bwlimit = 0; int bwlimit = 0; size_t bwlimit_writemax = 0; int delete_after = 0; int only_existing = 0; int opt_ignore_existing = 0; int max_delete = 0; +OFF_T max_size = 0; int ignore_errors = 0; int modify_window = 0; int blocking_io = -1; @@ -119,7 +121,7 @@ unsigned int backup_dir_remainder; char *backup_suffix = NULL; char *tmpdir = NULL; char *partial_dir = NULL; -char *compare_dest = NULL; +char *basis_dir[MAX_BASIS_DIRS+1]; char *config_file = NULL; char *shell_cmd = NULL; char *log_format = NULL; @@ -127,7 +129,8 @@ char *password_file = NULL; char *rsync_path = RSYNC_PATH; char *backup_dir = NULL; char backup_dir_buf[MAXPATHLEN]; -int rsync_port = RSYNC_PORT; +int rsync_port = 0; +int copy_dest = 0; int link_dest = 0; int verbose = 0; @@ -140,6 +143,10 @@ char *batch_name = NULL; static int daemon_opt; /* sets am_daemon after option error-reporting */ static int modify_window_set; +static int compare_dest = 0; +static int basis_dir_cnt = 0; +static char *dest_option; +static char *max_size_arg; /** Local address to bind. As a character string because it's * interpreted by the IPv6 layer: should be a numeric IP4 or IP6 @@ -268,6 +275,7 @@ void usage(enum logcode F) rprintf(F," --delete-after receiver deletes after transferring, not before\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); + rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); rprintf(F," --partial keep partially transferred files\n"); rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); rprintf(F," --force force deletion of directories even if not empty\n"); @@ -278,7 +286,8 @@ void usage(enum logcode F) rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n"); rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n"); rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n"); - rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n"); + rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n"); + rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n"); rprintf(F," -P equivalent to --partial --progress\n"); rprintf(F," -z, --compress compress file data\n"); rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n"); @@ -310,9 +319,10 @@ void usage(enum logcode F) } enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, - OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST, + OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, + OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, - OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, + OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE, OPT_REFUSED_BASE = 9000}; static struct poptOption long_options[] = { @@ -367,10 +377,12 @@ static struct poptOption long_options[] = { {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 }, {"block-size", 'B', POPT_ARG_INT, &block_size, 0, 0, 0 }, {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 }, + {"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 }, {"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 0, 0 }, {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 }, - {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 }, - {"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 }, + {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 }, + {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 }, + {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 }, /* TODO: Should this take an optional int giving the compression level? */ {"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 }, {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 }, @@ -411,6 +423,7 @@ static void daemon_usage(enum logcode F) rprintf(F,"\nUsage: rsync --daemon [OPTION]...\n"); rprintf(F," --address=ADDRESS bind to the specified address\n"); + rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n"); rprintf(F," --config=FILE specify alternate rsyncd.conf file\n"); rprintf(F," --no-detach do not detach from the parent\n"); rprintf(F," --port=PORT specify alternate rsyncd port number\n"); @@ -427,6 +440,7 @@ static void daemon_usage(enum logcode F) static struct poptOption long_daemon_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 }, + {"bwlimit", 0, POPT_ARG_INT, &daemon_bwlimit, 0, 0, 0 }, {"config", 0, POPT_ARG_STRING, &config_file, 0, 0, 0 }, {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 }, #ifdef INET6 @@ -544,6 +558,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) /* The context leaks in case of an error, but if there's a * problem we always exit anyhow. */ pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0); + poptReadDefaultConfig(pc, 0); while ((opt = poptGetNextOpt(pc)) != -1) { /* most options are handled automatically by popt; @@ -667,6 +682,35 @@ int parse_arguments(int *argc, const char ***argv, int frommain) read_batch = 1; break; + case OPT_MAX_SIZE: + for (arg = max_size_arg; isdigit(*arg); arg++) {} + if (*arg == '.') + for (arg++; isdigit(*arg); arg++) {} + switch (*arg) { + case 'k': case 'K': + max_size = atof(max_size_arg) * 1024; + break; + case 'm': case 'M': + max_size = atof(max_size_arg) * 1024*1024; + break; + case 'g': case 'G': + max_size = atof(max_size_arg) * 1024*1024*1024; + break; + case '\0': + max_size = atof(max_size_arg); + break; + default: + max_size = 0; + break; + } + if (max_size <= 0) { + snprintf(err_buf, sizeof err_buf, + "--max-size value is invalid: %s\n", + max_size_arg); + return 0; + } + break; + case OPT_TIMEOUT: if (io_timeout && io_timeout < select_timeout) select_timeout = io_timeout; @@ -675,7 +719,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain) case OPT_LINK_DEST: #if HAVE_LINK link_dest = 1; - break; + dest_option = "--link-dest"; + goto set_dest_dir; #else snprintf(err_buf, sizeof err_buf, "hard links are not supported on this %s\n", @@ -683,6 +728,27 @@ int parse_arguments(int *argc, const char ***argv, int frommain) return 0; #endif + case OPT_COPY_DEST: + copy_dest = 1; + dest_option = "--copy-dest"; + goto set_dest_dir; + + case OPT_COMPARE_DEST: + compare_dest = 1; + dest_option = "--compare-dest"; + set_dest_dir: + if (basis_dir_cnt >= MAX_BASIS_DIRS-1) { + snprintf(err_buf, sizeof err_buf, + "ERROR: at most %d %s args may be specified\n", + MAX_BASIS_DIRS, dest_option); + return 0; + } + arg = poptGetOptArg(pc); + if (sanitize_paths) + arg = sanitize_path(NULL, arg, NULL, 0); + basis_dir[basis_dir_cnt++] = (char *)arg; + break; + default: /* A large opt value means that set_refuse_options() * turned this option off (opt-BASE is its index). */ @@ -765,6 +831,12 @@ int parse_arguments(int *argc, const char ***argv, int frommain) return 0; } + if (compare_dest + copy_dest + link_dest > 1) { + snprintf(err_buf, sizeof err_buf, + "You may not mix --compare-dest, --copy-dest, and --link-dest.\n"); + return 0; + } + if (archive_mode) { if (!files_from) recurse = 1; @@ -792,8 +864,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain) tmpdir = sanitize_path(NULL, tmpdir, NULL, 0); if (partial_dir) partial_dir = sanitize_path(NULL, partial_dir, NULL, 0); - if (compare_dest) - compare_dest = sanitize_path(NULL, compare_dest, NULL, 0); if (backup_dir) backup_dir = sanitize_path(NULL, backup_dir, NULL, 0); if (files_from) @@ -801,6 +871,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) } if (server_exclude_list.head && !am_sender) { struct exclude_list_struct *elp = &server_exclude_list; + int i; if (tmpdir) { clean_fname(tmpdir, 1); if (check_exclude(elp, tmpdir, 1) < 0) @@ -811,9 +882,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (check_exclude(elp, partial_dir, 1) < 0) goto options_rejected; } - if (compare_dest) { - clean_fname(compare_dest, 1); - if (check_exclude(elp, compare_dest, 1) < 0) + for (i = 0; i < basis_dir_cnt; i++) { + clean_fname(basis_dir[i], 1); + if (check_exclude(elp, basis_dir[i], 1) < 0) goto options_rejected; } if (backup_dir) { @@ -864,6 +935,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (do_progress && !verbose) verbose = 1; + if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit)) + bwlimit = daemon_bwlimit; if (bwlimit) { bwlimit_writemax = (size_t)bwlimit * 128; if (bwlimit_writemax < 512) @@ -884,10 +957,10 @@ int parse_arguments(int *argc, const char ***argv, int frommain) am_server ? "server" : "client"); return 0; #endif - if (compare_dest) { + if (compare_dest || copy_dest || link_dest) { snprintf(err_buf, sizeof err_buf, "--inplace does not yet work with %s\n", - link_dest ? "--link-dest" : "--compare-dest"); + dest_option); return 0; } } else { @@ -951,8 +1024,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain) **/ void server_options(char **args,int *argc) { + static char argstr[50+MAX_BASIS_DIRS*2]; int ac = *argc; - static char argstr[50]; char *arg; int i, x; @@ -1050,6 +1123,11 @@ void server_options(char **args,int *argc) args[ac++] = arg; } + if (max_size && am_sender) { + args[ac++] = "--max-size"; + args[ac++] = max_size_arg; + } + if (io_timeout) { if (asprintf(&arg, "--timeout=%d", io_timeout) < 0) goto oom; @@ -1135,13 +1213,16 @@ void server_options(char **args,int *argc) args[ac++] = tmpdir; } - if (compare_dest && am_sender) { + if (basis_dir[0] && am_sender) { /* the server only needs this option if it is not the sender, * and it may be an older version that doesn't know this * option, so don't send it if client is the sender. */ - args[ac++] = link_dest ? "--link-dest" : "--compare-dest"; - args[ac++] = compare_dest; + int i; + for (i = 0; i < basis_dir_cnt; i++) { + args[ac++] = dest_option; + args[ac++] = basis_dir[i]; + } } if (files_from && (!am_sender || remote_filesfrom_file)) {