X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3ca9e5d8ad653317f1ff1a5dd7c7ae0bc419180a..19b8587654616db0b1a90de7d596ccafd882df19:/options.c diff --git a/options.c b/options.c index 527797f1..04a5654e 100644 --- a/options.c +++ b/options.c @@ -1,7 +1,9 @@ -/* -*- c-file-style: "linux" -*- +/* + * Command-line (and received via daemon-socket) option parsing. * - * Copyright (C) 1998-2001 by Andrew Tridgell - * Copyright (C) 2000, 2001, 2002 by Martin Pool + * Copyright (C) 1998-2001 Andrew Tridgell + * Copyright (C) 2000, 2001, 2002 Martin Pool + * Copyright (C) 2002, 2003, 2004, 2005, 2006 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,9 +15,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "rsync.h" @@ -41,6 +43,7 @@ int whole_file = -1; int append_mode = 0; int keep_dirlinks = 0; +int copy_dirlinks = 0; int copy_links = 0; int preserve_links = 0; int preserve_hard_links = 0; @@ -57,8 +60,6 @@ int cvs_exclude = 0; int dry_run = 0; int do_xfers = 1; int ignore_times = 0; -int saw_delete_opt = 0; -int saw_delete_excluded_opt = 0; int delete_mode = 0; int delete_during = 0; int delete_before = 0; @@ -75,7 +76,6 @@ int am_server = 0; int am_sender = 0; int am_generator = 0; int am_starting_up = 1; -int orig_umask = 0; int relative_paths = -1; int implied_dirs = 1; int numeric_ids = 0; @@ -147,7 +147,9 @@ char *partial_dir = NULL; char *basis_dir[MAX_BASIS_DIRS+1]; char *config_file = NULL; char *shell_cmd = NULL; -char *log_format = NULL; +char *logfile_name = NULL; +char *logfile_format = NULL; +char *stdout_format = NULL; char *password_file = NULL; char *rsync_path = RSYNC_PATH; char *backup_dir = NULL; @@ -163,8 +165,10 @@ char *dest_option = NULL; int verbose = 0; int quiet = 0; int log_before_transfer = 0; -int log_format_has_i = 0; -int log_format_has_o_or_i = 0; +int stdout_format_has_i = 0; +int stdout_format_has_o_or_i = 0; +int logfile_format_has_i = 0; +int logfile_format_has_o_or_i = 0; int always_checksum = 0; int list_only = 0; @@ -290,8 +294,9 @@ void usage(enum logcode F) rprintf(F," -L, --copy-links transform symlink into referent file/dir\n"); rprintf(F," --copy-unsafe-links only \"unsafe\" symlinks are transformed\n"); rprintf(F," --safe-links ignore symlinks that point outside the source tree\n"); - rprintf(F," -H, --hard-links preserve hard links\n"); + rprintf(F," -k, --copy-dirlinks transform symlink to a dir into referent dir\n"); rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); + rprintf(F," -H, --hard-links preserve hard links\n"); rprintf(F," -p, --perms preserve permissions\n"); rprintf(F," -E, --executability preserve the file's executability\n"); rprintf(F," --chmod=CHMOD change destination permissions\n"); @@ -310,15 +315,15 @@ void usage(enum logcode F) rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n"); rprintf(F," -e, --rsh=COMMAND specify the remote shell to use\n"); rprintf(F," --rsync-path=PROGRAM specify the rsync to run on the remote machine\n"); - rprintf(F," --existing ignore non-existing files on receiving side\n"); - rprintf(F," --ignore-existing ignore files that already exist on receiving side\n"); - rprintf(F," --remove-sent-files sent files/symlinks are removed from sending side\n"); + rprintf(F," --existing skip creating new files on receiver\n"); + rprintf(F," --ignore-existing skip updating files that already exist on receiver\n"); + rprintf(F," --remove-sent-files sender removes successfully sent files (non-dirs)\n"); rprintf(F," --del an alias for --delete-during\n"); - rprintf(F," --delete delete files that don't exist on the sending side\n"); + rprintf(F," --delete delete extraneous files from destination dirs\n"); rprintf(F," --delete-before receiver deletes before transfer (default)\n"); rprintf(F," --delete-during receiver deletes during transfer, not before\n"); rprintf(F," --delete-after receiver deletes after transfer, not before\n"); - rprintf(F," --delete-excluded also delete excluded files on the receiving side\n"); + rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); rprintf(F," --force force deletion of directories even if not empty\n"); rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); @@ -360,7 +365,9 @@ void usage(enum logcode F) rprintf(F," --progress show progress during transfer\n"); rprintf(F," -P same as --partial --progress\n"); rprintf(F," -i, --itemize-changes output a change-summary for all updates\n"); - rprintf(F," --log-format=FORMAT output filenames using the specified format\n"); + rprintf(F," --out-format=FORMAT output updates using the specified FORMAT\n"); + rprintf(F," --log-file=FILE log what we're doing to the specified FILE\n"); + rprintf(F," --log-file-format=FMT log updates using the specified FMT\n"); rprintf(F," --password-file=FILE read password from FILE\n"); rprintf(F," --list-only list the files instead of copying them\n"); rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n"); @@ -373,7 +380,7 @@ void usage(enum logcode F) rprintf(F," -6, --ipv6 prefer IPv6\n"); #endif rprintf(F," --version print version number\n"); - rprintf(F," --help show this help screen\n"); + rprintf(F,"(-h) --help show this help (-h works with no other options)\n"); rprintf(F,"\nUse \"rsync --daemon --help\" to see the daemon-mode command-line options.\n"); rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) man pages for full documentation.\n"); @@ -434,11 +441,15 @@ static struct poptOption long_options[] = { {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 }, {"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 }, {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 }, + {"copy-dirlinks", 'k', POPT_ARG_NONE, ©_dirlinks, 0, 0, 0 }, {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, - {"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 }, + {"hard-links", 'H', POPT_ARG_VAL, &preserve_hard_links, 1, 0, 0 }, + {"no-hard-links", 0, POPT_ARG_VAL, &preserve_hard_links, 0, 0, 0 }, + {"no-H", 0, POPT_ARG_VAL, &preserve_hard_links, 0, 0, 0 }, {"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 }, {"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 }, {"no-R", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 }, + {"implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 }, {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 }, {"chmod", 0, POPT_ARG_STRING, 0, OPT_CHMOD, 0, 0 }, {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 }, @@ -489,7 +500,10 @@ static struct poptOption long_options[] = { {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, {"delay-updates", 0, POPT_ARG_NONE, &delay_updates, 0, 0, 0 }, {"prune-empty-dirs",'m', POPT_ARG_NONE, &prune_empty_dirs, 0, 0, 0 }, - {"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 }, + {"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 }, + {"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 }, + {"out-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 }, + {"log-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 }, /* DEPRECATED */ {"itemize-changes", 'i', POPT_ARG_NONE, 0, 'i', 0, 0 }, {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 }, {"backup", 'b', POPT_ARG_NONE, &make_backups, 0, 0, 0 }, @@ -539,6 +553,8 @@ static void daemon_usage(enum logcode F) 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 listen on alternate port number\n"); + rprintf(F," --log-file=FILE override the \"log file\" setting\n"); + rprintf(F," --log-file-format=FMT override the \"log format\" setting\n"); rprintf(F," --sockopts=OPTIONS specify custom TCP options\n"); rprintf(F," -v, --verbose increase verbosity\n"); #ifdef INET6 @@ -562,6 +578,8 @@ static struct poptOption long_daemon_options[] = { {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 }, #endif {"detach", 0, POPT_ARG_VAL, &no_detach, 0, 0, 0 }, + {"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 }, + {"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 }, {"no-detach", 0, POPT_ARG_VAL, &no_detach, 1, 0, 0 }, {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 }, {"sockopts", 0, POPT_ARG_STRING, &sockopts, 0, 0, 0 }, @@ -592,6 +610,7 @@ void option_error(void) } rprintf(FERROR, RSYNC_NAME ": %s", err_buf); + msleep(20); } @@ -661,17 +680,6 @@ static void set_refuse_options(char *bp) *cp = ' '; bp = cp + 1; } - - for (op = long_options; ; op++) { - *shortname = op->shortName; - if (!op->longName && !*shortname) - break; - if (op->val == OPT_DAEMON) { - if (op->argInfo == POPT_ARG_VAL) - op->argInfo = POPT_ARG_NONE; - op->val = (op - long_options) + OPT_REFUSED_BASE; - } - } } @@ -776,6 +784,8 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (ref && *ref) set_refuse_options(ref); + if (am_daemon) + set_refuse_options("log-file*"); /* TODO: Call poptReadDefaultConfig; handle errors. */ @@ -884,15 +894,20 @@ int parse_arguments(int *argc, const char ***argv, int frommain) case OPT_EXCLUDE_FROM: case OPT_INCLUDE_FROM: arg = poptGetOptArg(pc); - if (sanitize_paths) - arg = sanitize_path(NULL, arg, NULL, 0); + if (sanitize_paths) { + arg = sanitize_path(NULL, arg, NULL, 0, NULL); + die_on_unsafe_path((char*)arg, 0); + } if (server_filter_list.head) { - char *cp = (char *)arg; + char *cp = strdup(arg); + if (!cp) + out_of_memory("parse_arguments"); if (!*cp) goto options_rejected; clean_fname(cp, 1); if (check_filter(&server_filter_list, cp, 0) < 0) goto options_rejected; + free(cp); } parse_filter_file(&filter_list, arg, opt == OPT_INCLUDE_FROM ? MATCHFLG_INCLUDE : 0, @@ -1016,7 +1031,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) break; case OPT_LINK_DEST: -#ifdef HAVE_LINK +#ifdef SUPPORT_HARD_LINKS link_dest = 1; dest_option = "--link-dest"; goto set_dest_dir; @@ -1042,10 +1057,9 @@ int parse_arguments(int *argc, const char ***argv, int frommain) 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; + /* We defer sanitizing this arg until we know what + * our destination directory is going to be. */ + basis_dir[basis_dir_cnt++] = (char *)poptGetOptArg(pc); break; case OPT_CHMOD: @@ -1172,11 +1186,10 @@ int parse_arguments(int *argc, const char ***argv, int frommain) } delete_mode = delete_before = 1; } - saw_delete_opt = delete_mode; - saw_delete_excluded_opt = delete_excluded; - if (!xfer_dirs) { - delete_before = delete_during = delete_after = 0; - delete_mode = delete_excluded = 0; + if (!xfer_dirs && delete_mode) { + snprintf(err_buf, sizeof err_buf, + "--delete does not work without -r or -d.\n"); + return 0; } if (delete_mode && refused_delete) { @@ -1201,17 +1214,18 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (sanitize_paths) { int i; for (i = *argc; i-- > 0; ) - (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0); - if (tmpdir) - tmpdir = sanitize_path(NULL, tmpdir, NULL, 0); - if (partial_dir) - partial_dir = sanitize_path(NULL, partial_dir, NULL, 0); - if (backup_dir) - backup_dir = sanitize_path(NULL, backup_dir, NULL, 0); + (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0, NULL); + if (tmpdir) { + tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, NULL); + die_on_unsafe_path(tmpdir, 0); + } + if (backup_dir) { + backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, NULL); + die_on_unsafe_path(backup_dir, 0); + } } if (server_filter_list.head && !am_sender) { struct filter_list_struct *elp = &server_filter_list; - int i; if (tmpdir) { if (!*tmpdir) goto options_rejected; @@ -1219,18 +1233,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (check_filter(elp, tmpdir, 1) < 0) goto options_rejected; } - if (partial_dir && *partial_dir) { - clean_fname(partial_dir, 1); - if (check_filter(elp, partial_dir, 1) < 0) - goto options_rejected; - } - for (i = 0; i < basis_dir_cnt; i++) { - if (!*basis_dir[i]) - goto options_rejected; - clean_fname(basis_dir[i], 1); - if (check_filter(elp, basis_dir[i], 1) < 0) - goto options_rejected; - } if (backup_dir) { if (!*backup_dir) goto options_rejected; @@ -1279,17 +1281,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain) if (make_backups && !backup_dir) omit_dir_times = 1; - if (log_format) { - if (am_server && log_format_has(log_format, 'I')) - log_format_has_i = 2; - else if (log_format_has(log_format, 'i')) - log_format_has_i = itemize_changes | 1; - if (!log_format_has(log_format, 'b') - && !log_format_has(log_format, 'c')) + if (stdout_format) { + if (am_server && log_format_has(stdout_format, 'I')) + stdout_format_has_i = 2; + else if (log_format_has(stdout_format, 'i')) + stdout_format_has_i = itemize_changes | 1; + if (!log_format_has(stdout_format, 'b') + && !log_format_has(stdout_format, 'c')) log_before_transfer = !am_server; } else if (itemize_changes) { - log_format = "%i %n%L"; - log_format_has_i = itemize_changes; + stdout_format = "%i %n%L"; + stdout_format_has_i = itemize_changes; log_before_transfer = !am_server; } @@ -1301,12 +1303,26 @@ int parse_arguments(int *argc, const char ***argv, int frommain) set_io_timeout(io_timeout); - if (verbose && !log_format) { - log_format = "%n%L"; + if (verbose && !stdout_format) { + stdout_format = "%n%L"; log_before_transfer = !am_server; } - if (log_format_has_i || log_format_has(log_format, 'o')) - log_format_has_o_or_i = 1; + if (stdout_format_has_i || log_format_has(stdout_format, 'o')) + stdout_format_has_o_or_i = 1; + + if (logfile_name && !am_daemon) { + if (!logfile_format) { + logfile_format = "%i %n%L"; + logfile_format_has_i = logfile_format_has_o_or_i = 1; + } else { + if (log_format_has(logfile_format, 'i')) + logfile_format_has_i = 1; + if (logfile_format_has_i || log_format_has(logfile_format, 'o')) + logfile_format_has_o_or_i = 1; + } + log_init(); + } else if (!am_daemon) + logfile_format = NULL; if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit)) bwlimit = daemon_bwlimit; @@ -1411,7 +1427,7 @@ int parse_arguments(int *argc, const char ***argv, int frommain) } } else { if (sanitize_paths) - files_from = sanitize_path(NULL, files_from, NULL, 0); + files_from = sanitize_path(NULL, files_from, NULL, 0, NULL); if (server_filter_list.head) { if (!*files_from) goto options_rejected; @@ -1477,12 +1493,10 @@ void server_options(char **args,int *argc) argstr[x++] = 'b'; if (update_only) argstr[x++] = 'u'; - if (!do_xfers) /* NOT "dry_run"! */ + if (!do_xfers) /* Note: NOT "dry_run"! */ argstr[x++] = 'n'; if (preserve_links) argstr[x++] = 'l'; - if (copy_links) - argstr[x++] = 'L'; if (xfer_dirs > (recurse || !delete_mode || !am_sender)) argstr[x++] = 'd'; if (am_sender) { @@ -1492,6 +1506,11 @@ void server_options(char **args,int *argc) argstr[x++] = 'm'; if (omit_dir_times == 2) argstr[x++] = 'O'; + } else { + if (copy_links) + argstr[x++] = 'L'; + if (copy_dirlinks) + argstr[x++] = 'k'; } if (whole_file > 0) @@ -1568,12 +1587,13 @@ void server_options(char **args,int *argc) /* The server side doesn't use our log-format, but in certain * circumstances they need to know a little about the option. */ - if (log_format && am_sender) { - if (log_format_has_i > 1) + if (stdout_format && am_sender) { + /* Use --log-format, not --out-format, for compatibility. */ + if (stdout_format_has_i > 1) args[ac++] = "--log-format=%i%I"; - else if (log_format_has_i) + else if (stdout_format_has_i) args[ac++] = "--log-format=%i"; - else if (log_format_has_o_or_i) + else if (stdout_format_has_o_or_i) args[ac++] = "--log-format=%o"; else if (!verbose) args[ac++] = "--log-format=X"; @@ -1643,11 +1663,10 @@ void server_options(char **args,int *argc) args[ac++] = "--only-write-batch=X"; if (am_root > 1) args[ac++] = "--super"; + if (size_only) + args[ac++] = "--size-only"; } - if (size_only) - args[ac++] = "--size-only"; - if (modify_window_set) { if (asprintf(&arg, "--modify-window=%d", modify_window) < 0) goto oom;