/* -*- c-file-style: "linux" -*-
Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
- Copyright (C) 2000-2001 by Martin Pool <mbp@samba.org>
+ Copyright (C) 2000, 2001, 2002 by Martin Pool <mbp@samba.org>
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
#include "popt.h"
int make_backups = 0;
-int whole_file = 0;
+int whole_file = -1;
int copy_links = 0;
int preserve_links = 0;
int preserve_hard_links = 0;
int read_only = 0;
int module_id = -1;
int am_server = 0;
-int am_sender=0;
+int am_sender = 0;
int recurse = 0;
int am_daemon=0;
int do_stats=0;
int bwlimit=0;
int delete_after=0;
int only_existing=0;
+int opt_ignore_existing=0;
int max_delete=0;
int ignore_errors=0;
#ifdef _WIN32
#else
int modify_window=0;
#endif
-int blocking_io=0;
+int blocking_io=-1;
+
+/** Network address family. **/
+#ifdef INET6
+int default_af_hint = 0; /* Any protocol */
+#else
+int default_af_hint = AF_INET; /* Must use IPv4 */
+#endif
+
+/** Do not go into the background when run as --daemon. Good
+ * for debugging and required for running as a service on W32,
+ * or under Unix process-monitors. **/
+int no_detach = 0;
+
+int write_batch = 0;
+int read_batch = 0;
char *backup_suffix = BACKUP_SUFFIX;
char *tmpdir = NULL;
char *shell_cmd = NULL;
char *log_format = NULL;
char *password_file = NULL;
-char *rsync_path = RSYNC_NAME;
+char *rsync_path = RSYNC_PATH;
char *backup_dir = NULL;
int rsync_port = RSYNC_PORT;
int always_checksum = 0;
int list_only = 0;
-static int modify_window_set;
+char *batch_prefix = NULL;
+static int modify_window_set;
-struct in_addr socket_address = {INADDR_ANY};
+/** Local address to bind. As a character string because it's
+ * interpreted by the IPv6 layer: should be a numeric IP4 or ip6
+ * address, or a hostname. **/
+char *bind_address;
-static void print_rsync_version(int f)
+static void print_rsync_version(enum logcode f)
{
char const *got_socketpair = "no ";
char const *hardlinks = "no ";
char const *links = "no ";
+ char const *ipv6 = "no ";
+ STRUCT_STAT *dumstat;
#ifdef HAVE_SOCKETPAIR
got_socketpair = "";
links = "";
#endif
+#if INET6
+ ipv6 = "";
+#endif
+
rprintf(f, "%s version %s protocol version %d\n",
- RSYNC_NAME, VERSION, PROTOCOL_VERSION);
+ RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
rprintf(f,
- "Copyright (C) 1996-2001 by Andrew Tridgell, Paul Mackerras and others\n");
+ "Copyright (C) 1996-2002 by Andrew Tridgell and others\n");
+ rprintf(f, "<http://rsync.samba.org/>\n");
rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
- "%shard links, %ssymlinks\n\n",
- sizeof(int64) * 8,
- got_socketpair,
- hardlinks, links);
+ "%shard links, %ssymlinks, batchfiles, %sIPv6,\n",
+ (int) (sizeof(OFF_T) * 8),
+ got_socketpair, hardlinks, links, ipv6);
+
+ /* Note that this field may not have type ino_t. It depends
+ * on the complicated interaction between largefile feature
+ * macros. */
+ rprintf(f, " %d-bit system inums, %d-bit internal inums\n",
+ (int) (sizeof(dumstat->st_ino) * 8),
+ (int) (sizeof(INO64_T) * 8));
#ifdef NO_INT64
- rprintf(logcode, "WARNING: no 64-bit integers on this platform!\n");
+ rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
#endif
}
rprintf(F," --backup-dir make backups into this directory\n");
rprintf(F," --suffix=SUFFIX override backup suffix\n");
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
- rprintf(F," -l, --links preserve soft links\n");
- rprintf(F," -L, --copy-links treat soft links like regular files\n");
+ rprintf(F," -l, --links copy symlinks as symlinks\n");
+ rprintf(F," -L, --copy-links copy the referent of symlinks\n");
rprintf(F," --copy-unsafe-links copy links outside the source tree\n");
rprintf(F," --safe-links ignore links outside the destination tree\n");
rprintf(F," -H, --hard-links preserve hard links\n");
rprintf(F," -S, --sparse handle sparse files efficiently\n");
rprintf(F," -n, --dry-run show what would have been transferred\n");
rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
+ rprintf(F," --no-whole-file turn off --whole-file\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F," -B, --block-size=SIZE checksum blocking size (default %d)\n",BLOCK_SIZE);
rprintf(F," -e, --rsh=COMMAND specify rsh replacement\n");
rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
rprintf(F," --existing only update files that already exist\n");
+ rprintf(F," --ignore-existing ignore files that already exist on the receiving side\n");
rprintf(F," --delete delete files that don't exist on the sending side\n");
rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
rprintf(F," --delete-after delete after transferring, not before\n");
rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as a rsync daemon\n");
- rprintf(F," --address bind to the specified address\n");
+ rprintf(F," --no-detach do not detach from the parent\n");
+ rprintf(F," --address=ADDRESS bind to the specified address\n");
rprintf(F," --config=FILE specify alternate rsyncd.conf file\n");
rprintf(F," --port=PORT specify alternate rsyncd port number\n");
rprintf(F," --blocking-io use blocking IO for the remote shell\n");
+ rprintf(F," --no-blocking-io turn off --blocking-io\n");
rprintf(F," --stats give some file transfer stats\n");
rprintf(F," --progress show progress during transfer\n");
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," --write-batch=PREFIX write batch fileset starting with PREFIX\n");
+ rprintf(F," --read-batch=PREFIX read batch fileset starting with PREFIX\n");
rprintf(F," -h, --help show this help screen\n");
+#ifdef INET6
+ rprintf(F," -4 prefer IPv4\n");
+ rprintf(F," -6 prefer IPv6\n");
+#endif
rprintf(F,"\n");
OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS,
OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR,
OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO,
- OPT_MODIFY_WINDOW};
+ OPT_NO_BLOCKING_IO, OPT_NO_WHOLE_FILE,
+ OPT_MODIFY_WINDOW, OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_IGNORE_EXISTING};
static struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
{"one-file-system", 'x', POPT_ARG_NONE, &one_file_system},
{"delete", 0, POPT_ARG_NONE, &delete_mode},
{"existing", 0, POPT_ARG_NONE, &only_existing},
+ {"ignore-existing", 0, POPT_ARG_NONE, &opt_ignore_existing},
{"delete-after", 0, POPT_ARG_NONE, &delete_after},
{"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED},
{"force", 0, POPT_ARG_NONE, &force_delete},
{"update", 'u', POPT_ARG_NONE, &update_only},
{"links", 'l', POPT_ARG_NONE, &preserve_links},
{"copy-links", 'L', POPT_ARG_NONE, ©_links},
- {"whole", 'W', POPT_ARG_NONE, &whole_file},
+ {"whole-file", 'W', POPT_ARG_NONE, &whole_file},
+ {"no-whole-file", 0, POPT_ARG_NONE, 0, OPT_NO_WHOLE_FILE},
{"copy-unsafe-links", 0, POPT_ARG_NONE, ©_unsafe_links},
{"perms", 'p', POPT_ARG_NONE, &preserve_perms},
{"owner", 'o', POPT_ARG_NONE, &preserve_uid},
{"archive", 'a', POPT_ARG_NONE, 0, 'a'},
{"server", 0, POPT_ARG_NONE, &am_server},
{"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER},
- {"recurse", 'r', POPT_ARG_NONE, &recurse},
+ {"recursive", 'r', POPT_ARG_NONE, &recurse},
{"relative", 'R', POPT_ARG_NONE, &relative_paths},
{"rsh", 'e', POPT_ARG_STRING, &shell_cmd},
{"block-size", 'B', POPT_ARG_INT, &block_size},
{"max-delete", 0, POPT_ARG_INT, &max_delete},
{"timeout", 0, POPT_ARG_INT, &io_timeout},
{"temp-dir", 'T', POPT_ARG_STRING, &tmpdir},
- {"compare-dest", 0, POPT_ARG_NONE, &compare_dest},
+ {"compare-dest", 0, POPT_ARG_STRING, &compare_dest},
/* TODO: Should this take an optional int giving the compression level? */
{"compress", 'z', POPT_ARG_NONE, &do_compression},
{"daemon", 0, POPT_ARG_NONE, &am_daemon},
+ {"no-detach", 0, POPT_ARG_NONE, &no_detach},
{"stats", 0, POPT_ARG_NONE, &do_stats},
{"progress", 0, POPT_ARG_NONE, &do_progress},
{"partial", 0, POPT_ARG_NONE, &keep_partial},
{"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors},
{"blocking-io", 0, POPT_ARG_NONE, &blocking_io},
+ {"no-blocking-io", 0, POPT_ARG_NONE, 0, OPT_NO_BLOCKING_IO},
{0, 'P', POPT_ARG_NONE, 0, 'P'},
{"config", 0, POPT_ARG_STRING, &config_file},
{"port", 0, POPT_ARG_INT, &rsync_port},
{"log-format", 0, POPT_ARG_STRING, &log_format},
{"bwlimit", 0, POPT_ARG_INT, &bwlimit},
- {"address", 0, POPT_ARG_STRING, 0, OPT_ADDRESS},
+ {"address", 0, POPT_ARG_STRING, &bind_address, 0},
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir},
{"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links},
+ {"read-batch", 0, POPT_ARG_STRING, &batch_prefix, OPT_READ_BATCH},
+ {"write-batch", 0, POPT_ARG_STRING, &batch_prefix, OPT_WRITE_BATCH},
+#ifdef INET6
+ {0, '4', POPT_ARG_VAL, &default_af_hint, AF_INET },
+ {0, '6', POPT_ARG_VAL, &default_af_hint, AF_INET6 },
+#endif
{0,0,0,0}
};
static char err_buf[100];
+/* We store the option error message, if any, so that we can log the
+ connection attempt (which requires parsing the options), and then
+ show the error later on. */
void option_error(void)
{
if (err_buf[0]) {
rprintf(FLOG, "%s", err_buf);
rprintf(FERROR, "%s: %s", RSYNC_NAME, err_buf);
} else {
- rprintf(FLOG,"Error parsing options - unsupported option?\n");
- rprintf(FERROR,"Error parsing options - unsupported option?\n");
+ rprintf (FERROR, "Error parsing options: "
+ "option may be supported on client but not on server?\n");
+ rprintf (FERROR, RSYNC_NAME ": Error parsing options: "
+ "option may be supported on client but not on server?\n");
}
}
while ((p = strstr(ref,name))) {
if ((p==ref || p[-1]==' ') &&
(p[len] == ' ' || p[len] == 0)) {
- slprintf(err_buf,sizeof(err_buf),
+ snprintf(err_buf,sizeof(err_buf),
"The '%s' option is not supported by this server\n", name);
return 1;
}
/* The context leaks in case of an error, but if there's a
* problem we always exit anyhow. */
- pc = poptGetContext(RSYNC_NAME, *argc, (const char **) *argv,
- long_options, 0);
+ pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
while ((opt = poptGetNextOpt(pc)) != -1) {
if (ref) {
add_exclude_file(poptGetOptArg(pc), 1, 0);
break;
- case OPT_INCLUDE_FROM:
- add_exclude_file(poptGetOptArg(pc), 1, 1);
+ case OPT_NO_WHOLE_FILE:
+ whole_file = 0;
+ break;
+
+ case OPT_NO_BLOCKING_IO:
+ blocking_io = 0;
break;
case 'h':
* rprintf? Everybody who gets this message
* ought to send it to the client and also to
* the logs. */
- slprintf(err_buf,sizeof(err_buf),
+ snprintf(err_buf,sizeof(err_buf),
"hard links are not supported on this %s\n",
am_server ? "server" : "client");
rprintf(FERROR,"ERROR: hard links not supported on this platform\n");
keep_partial = 1;
break;
- case OPT_ADDRESS:
- {
- struct in_addr *ia;
- if ((ia = ip_address(optarg))) {
- socket_address = *ia;
- }
- }
+ case OPT_WRITE_BATCH:
+ /* popt stores the filename in batch_prefix for us */
+ write_batch = 1;
+ break;
+
+ case OPT_READ_BATCH:
+ /* popt stores the filename in batch_prefix for us */
+ read_batch = 1;
break;
default:
/* FIXME: If --daemon is specified, then errors for later
* parameters seem to disappear. */
- slprintf(err_buf, sizeof(err_buf),
+ snprintf(err_buf, sizeof(err_buf),
"%s%s: %s\n",
am_server ? "on remote machine: " : "",
poptBadOption(pc, POPT_BADOPTION_NOALIAS),
}
}
+ if (write_batch && read_batch) {
+ snprintf(err_buf,sizeof(err_buf),
+ "write-batch and read-batch can not be used together\n");
+ rprintf(FERROR,"ERROR: write-batch and read-batch"
+ " can not be used together\n");
+ return 0;
+ }
+
+ if (do_compression && (write_batch || read_batch)) {
+ snprintf(err_buf,sizeof(err_buf),
+ "compress can not be used with write-batch or read-batch\n");
+ rprintf(FERROR,"ERROR: compress can not be used with"
+ " write-batch or read-batch\n");
+ return 0;
+ }
+
*argv = poptGetArgs(pc);
if (*argv)
*argc = count_args(*argv);
static char mdelete[30];
static char mwindow[30];
static char bw[50];
+ /* Leave room for ``--(write|read)-batch='' */
+ static char fext[MAXPATHLEN + 15];
int i, x;
+ if (whole_file == -1)
+ whole_file = 0;
+ if (blocking_io == -1)
+ blocking_io = 0;
+
args[ac++] = "--server";
if (!am_sender)
if (x != 1) args[ac++] = argstr;
if (block_size != BLOCK_SIZE) {
- slprintf(bsize,sizeof(bsize),"-B%d",block_size);
+ snprintf(bsize,sizeof(bsize),"-B%d",block_size);
args[ac++] = bsize;
}
if (max_delete && am_sender) {
- slprintf(mdelete,sizeof(mdelete),"--max-delete=%d",max_delete);
+ snprintf(mdelete,sizeof(mdelete),"--max-delete=%d",max_delete);
args[ac++] = mdelete;
}
+
+ if (batch_prefix != NULL) {
+ char *fmt = "";
+ if (write_batch)
+ fmt = "--write-batch=%s";
+ else
+ if (read_batch)
+ fmt = "--read-batch=%s";
+ snprintf(fext,sizeof(fext),fmt,batch_prefix);
+ args[ac++] = fext;
+ }
if (io_timeout) {
- slprintf(iotime,sizeof(iotime),"--timeout=%d",io_timeout);
+ snprintf(iotime,sizeof(iotime),"--timeout=%d",io_timeout);
args[ac++] = iotime;
}
if (bwlimit) {
- slprintf(bw,sizeof(bw),"--bwlimit=%d",bwlimit);
+ snprintf(bw,sizeof(bw),"--bwlimit=%d",bwlimit);
args[ac++] = bw;
}
args[ac++] = "--size-only";
if (modify_window_set) {
- slprintf(mwindow,sizeof(mwindow),"--modify-window=%d",
+ snprintf(mwindow,sizeof(mwindow),"--modify-window=%d",
modify_window);
args[ac++] = mwindow;
}
if (only_existing && am_sender)
args[ac++] = "--existing";
+ if (opt_ignore_existing && am_sender)
+ args[ac++] = "--ignore-existing";
+
if (tmpdir) {
args[ac++] = "--temp-dir";
args[ac++] = tmpdir;