Changed -h to be an alias for --human-readable (getting rid of -m).
[rsync/rsync.git] / options.c
1 /*  -*- c-file-style: "linux" -*-
2  *
3  * Copyright (C) 1998-2001 by Andrew Tridgell <tridge@samba.org>
4  * Copyright (C) 2000, 2001, 2002 by Martin Pool <mbp@samba.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "rsync.h"
22 #include "popt.h"
23 #include "zlib/zlib.h"
24
25 extern int module_id;
26 extern int sanitize_paths;
27 extern struct filter_list_struct filter_list;
28 extern struct filter_list_struct server_filter_list;
29
30 int make_backups = 0;
31
32 /**
33  * If 1, send the whole file as literal data rather than trying to
34  * create an incremental diff.
35  *
36  * If -1, then look at whether we're local or remote and go by that.
37  *
38  * @sa disable_deltas_p()
39  **/
40 int whole_file = -1;
41
42 int append_mode = 0;
43 int keep_dirlinks = 0;
44 int copy_links = 0;
45 int preserve_links = 0;
46 int preserve_hard_links = 0;
47 int preserve_perms = 0;
48 int preserve_devices = 0;
49 int preserve_uid = 0;
50 int preserve_gid = 0;
51 int preserve_times = 0;
52 int omit_dir_times = 0;
53 int update_only = 0;
54 int cvs_exclude = 0;
55 int dry_run = 0;
56 int do_xfers = 1;
57 int ignore_times = 0;
58 int delete_mode = 0;
59 int delete_during = 0;
60 int delete_before = 0;
61 int delete_after = 0;
62 int delete_excluded = 0;
63 int remove_sent_files = 0;
64 int one_file_system = 0;
65 int protocol_version = PROTOCOL_VERSION;
66 int sparse_files = 0;
67 int do_compression = 0;
68 int def_compress_level = Z_DEFAULT_COMPRESSION;
69 int am_root = 0;
70 int am_server = 0;
71 int am_sender = 0;
72 int am_generator = 0;
73 int am_starting_up = 1;
74 int orig_umask = 0;
75 int relative_paths = -1;
76 int implied_dirs = 1;
77 int numeric_ids = 0;
78 int force_delete = 0;
79 int io_timeout = 0;
80 int allowed_lull = 0;
81 char *files_from = NULL;
82 int filesfrom_fd = -1;
83 char *filesfrom_host = NULL;
84 int eol_nulls = 0;
85 int human_readable = 0;
86 int recurse = 0;
87 int xfer_dirs = -1;
88 int am_daemon = 0;
89 int daemon_over_rsh = 0;
90 int do_stats = 0;
91 int do_progress = 0;
92 int keep_partial = 0;
93 int safe_symlinks = 0;
94 int copy_unsafe_links = 0;
95 int size_only = 0;
96 int daemon_bwlimit = 0;
97 int bwlimit = 0;
98 int fuzzy_basis = 0;
99 size_t bwlimit_writemax = 0;
100 int ignore_existing = 0;
101 int ignore_non_existing = 0;
102 int need_messages_from_generator = 0;
103 int max_delete = 0;
104 OFF_T max_size = 0;
105 OFF_T min_size = 0;
106 int ignore_errors = 0;
107 int modify_window = 0;
108 int blocking_io = -1;
109 int checksum_seed = 0;
110 int inplace = 0;
111 int delay_updates = 0;
112 long block_size = 0; /* "long" because popt can't set an int32. */
113
114
115 /** Network address family. **/
116 #ifdef INET6
117 int default_af_hint = 0;        /* Any protocol */
118 #else
119 int default_af_hint = AF_INET;  /* Must use IPv4 */
120 #endif
121
122 /** Do not go into the background when run as --daemon.  Good
123  * for debugging and required for running as a service on W32,
124  * or under Unix process-monitors. **/
125 int no_detach
126 #if defined _WIN32 || defined __WIN32__
127         = 1;
128 #else
129         = 0;
130 #endif
131
132 int write_batch = 0;
133 int read_batch = 0;
134 int backup_dir_len = 0;
135 int backup_suffix_len;
136 unsigned int backup_dir_remainder;
137
138 char *backup_suffix = NULL;
139 char *tmpdir = NULL;
140 char *partial_dir = NULL;
141 char *basis_dir[MAX_BASIS_DIRS+1];
142 char *config_file = NULL;
143 char *shell_cmd = NULL;
144 char *log_format = NULL;
145 char *password_file = NULL;
146 char *rsync_path = RSYNC_PATH;
147 char *backup_dir = NULL;
148 char *chmod_mode = NULL;
149 char backup_dir_buf[MAXPATHLEN];
150 int rsync_port = 0;
151 int compare_dest = 0;
152 int copy_dest = 0;
153 int link_dest = 0;
154 int basis_dir_cnt = 0;
155 char *dest_option = NULL;
156
157 int verbose = 0;
158 int quiet = 0;
159 int log_before_transfer = 0;
160 int log_format_has_i = 0;
161 int log_format_has_o_or_i = 0;
162 int always_checksum = 0;
163 int list_only = 0;
164
165 #define MAX_BATCH_NAME_LEN 256  /* Must be less than MAXPATHLEN-13 */
166 char *batch_name = NULL;
167
168 struct chmod_mode_struct *chmod_modes = NULL;
169
170 static int daemon_opt;   /* sets am_daemon after option error-reporting */
171 static int F_option_cnt = 0;
172 static int modify_window_set;
173 static int itemize_changes = 0;
174 static int refused_delete, refused_archive_part, refused_compress;
175 static int refused_partial, refused_progress, refused_delete_before;
176 static int refused_inplace;
177 static char *max_size_arg, *min_size_arg;
178 static char partialdir_for_delayupdate[] = ".~tmp~";
179
180 /** Local address to bind.  As a character string because it's
181  * interpreted by the IPv6 layer: should be a numeric IP4 or IP6
182  * address, or a hostname. **/
183 char *bind_address;
184
185
186 static void print_rsync_version(enum logcode f)
187 {
188         char const *got_socketpair = "no ";
189         char const *have_inplace = "no ";
190         char const *hardlinks = "no ";
191         char const *links = "no ";
192         char const *ipv6 = "no ";
193         STRUCT_STAT *dumstat;
194
195 #ifdef HAVE_SOCKETPAIR
196         got_socketpair = "";
197 #endif
198
199 #ifdef HAVE_FTRUNCATE
200         have_inplace = "";
201 #endif
202
203 #ifdef SUPPORT_HARD_LINKS
204         hardlinks = "";
205 #endif
206
207 #ifdef SUPPORT_LINKS
208         links = "";
209 #endif
210
211 #ifdef INET6
212         ipv6 = "";
213 #endif
214
215         rprintf(f, "%s  version %s  protocol version %d\n",
216                 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
217         rprintf(f,
218                 "Copyright (C) 1996-2005 by Andrew Tridgell and others\n");
219         rprintf(f, "<http://rsync.samba.org/>\n");
220         rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
221                 "%shard links, %ssymlinks, batchfiles, \n",
222                 (int) (sizeof (OFF_T) * 8),
223                 got_socketpair, hardlinks, links);
224
225         /* Note that this field may not have type ino_t.  It depends
226          * on the complicated interaction between largefile feature
227          * macros. */
228         rprintf(f, "              %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
229                 have_inplace, ipv6,
230                 (int) (sizeof dumstat->st_ino * 8),
231                 (int) (sizeof (int64) * 8));
232 #ifdef MAINTAINER_MODE
233         rprintf(f, "              panic action: \"%s\"\n",
234                 get_panic_action());
235 #endif
236
237 #if SIZEOF_INT64 < 8
238         rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
239 #endif
240         if (sizeof (int64) != SIZEOF_INT64) {
241                 rprintf(f,
242                         "WARNING: size mismatch in SIZEOF_INT64 define (%d != %d)\n",
243                         (int) SIZEOF_INT64, (int) sizeof (int64));
244         }
245
246         rprintf(f,
247 "\n"
248 "rsync comes with ABSOLUTELY NO WARRANTY.  This is free software, and you\n"
249 "are welcome to redistribute it under certain conditions.  See the GNU\n"
250 "General Public Licence for details.\n"
251                 );
252 }
253
254
255 void usage(enum logcode F)
256 {
257   print_rsync_version(F);
258
259   rprintf(F,"\nrsync is a file transfer program capable of efficient remote update\nvia a fast differencing algorithm.\n\n");
260
261   rprintf(F,"Usage: rsync [OPTION]... SRC [SRC]... DEST\n");
262   rprintf(F,"  or   rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST\n");
263   rprintf(F,"  or   rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST\n");
264   rprintf(F,"  or   rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST\n");
265   rprintf(F,"  or   rsync [OPTION]... [USER@]HOST:SRC [DEST]\n");
266   rprintf(F,"  or   rsync [OPTION]... [USER@]HOST::SRC [DEST]\n");
267   rprintf(F,"  or   rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]\n");
268   rprintf(F,"The ':' usages connect via remote shell, while '::' & 'rsync://' usages connect\n");
269   rprintf(F,"to an rsync daemon, and require SRC or DEST to start with a module name.\n");
270   rprintf(F,"\nOptions\n");
271   rprintf(F," -v, --verbose               increase verbosity\n");
272   rprintf(F," -q, --quiet                 suppress non-error messages\n");
273   rprintf(F," -c, --checksum              skip based on checksum, not mod-time & size\n");
274   rprintf(F," -a, --archive               archive mode; same as -rlptgoD (no -H)\n");
275   rprintf(F,"     --no-OPTION             turn of an implied OPTION (e.g. --no-D)\n");
276   rprintf(F," -r, --recursive             recurse into directories\n");
277   rprintf(F," -R, --relative              use relative path names\n");
278   rprintf(F,"     --no-implied-dirs       don't send implied dirs with --relative\n");
279   rprintf(F," -b, --backup                make backups (see --suffix & --backup-dir)\n");
280   rprintf(F,"     --backup-dir=DIR        make backups into hierarchy based in DIR\n");
281   rprintf(F,"     --suffix=SUFFIX         set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
282   rprintf(F," -u, --update                skip files that are newer on the receiver\n");
283   rprintf(F,"     --inplace               update destination files in-place (SEE MAN PAGE)\n");
284   rprintf(F,"     --append                append data onto shorter files\n");
285   rprintf(F," -d, --dirs                  transfer directories without recursing\n");
286   rprintf(F," -l, --links                 copy symlinks as symlinks\n");
287   rprintf(F," -L, --copy-links            transform symlink into referent file/dir\n");
288   rprintf(F,"     --copy-unsafe-links     only \"unsafe\" symlinks are transformed\n");
289   rprintf(F,"     --safe-links            ignore symlinks that point outside the source tree\n");
290   rprintf(F," -H, --hard-links            preserve hard links\n");
291   rprintf(F," -K, --keep-dirlinks         treat symlinked dir on receiver as dir\n");
292   rprintf(F," -p, --perms                 preserve permissions\n");
293   rprintf(F," -o, --owner                 preserve owner (root only)\n");
294   rprintf(F," -g, --group                 preserve group\n");
295   rprintf(F," -D, --devices               preserve devices (root only)\n");
296   rprintf(F," -t, --times                 preserve times\n");
297   rprintf(F," -O, --omit-dir-times        omit directories when preserving times\n");
298   rprintf(F,"     --chmod=CHMOD           change destination permissions\n");
299   rprintf(F," -S, --sparse                handle sparse files efficiently\n");
300   rprintf(F," -n, --dry-run               show what would have been transferred\n");
301   rprintf(F," -W, --whole-file            copy files whole (without rsync algorithm)\n");
302   rprintf(F," -x, --one-file-system       don't cross filesystem boundaries\n");
303   rprintf(F," -B, --block-size=SIZE       force a fixed checksum block-size\n");
304   rprintf(F," -e, --rsh=COMMAND           specify the remote shell to use\n");
305   rprintf(F,"     --rsync-path=PROGRAM    specify the rsync to run on the remote machine\n");
306   rprintf(F,"     --ignore-existing       ignore files that already exist on receiving side\n");
307   rprintf(F,"     --ignore-non-existing   ignore files that don't exist on receiving side\n");
308   rprintf(F,"     --remove-sent-files     sent files/symlinks are removed from sending side\n");
309   rprintf(F,"     --del                   an alias for --delete-during\n");
310   rprintf(F,"     --delete                delete files that don't exist on the sending side\n");
311   rprintf(F,"     --delete-before         receiver deletes before transfer (default)\n");
312   rprintf(F,"     --delete-during         receiver deletes during transfer, not before\n");
313   rprintf(F,"     --delete-after          receiver deletes after transfer, not before\n");
314   rprintf(F,"     --delete-excluded       also delete excluded files on the receiving side\n");
315   rprintf(F,"     --ignore-errors         delete even if there are I/O errors\n");
316   rprintf(F,"     --force                 force deletion of directories even if not empty\n");
317   rprintf(F,"     --max-delete=NUM        don't delete more than NUM files\n");
318   rprintf(F,"     --max-size=SIZE         don't transfer any file larger than SIZE\n");
319   rprintf(F,"     --min-size=SIZE         don't transfer any file smaller than SIZE\n");
320   rprintf(F,"     --partial               keep partially transferred files\n");
321   rprintf(F,"     --partial-dir=DIR       put a partially transferred file into DIR\n");
322   rprintf(F,"     --delay-updates         put all updated files into place at transfer's end\n");
323   rprintf(F,"     --numeric-ids           don't map uid/gid values by user/group name\n");
324   rprintf(F,"     --timeout=TIME          set I/O timeout in seconds\n");
325   rprintf(F," -I, --ignore-times          don't skip files that match in size and mod-time\n");
326   rprintf(F,"     --size-only             skip files that match in size\n");
327   rprintf(F,"     --modify-window=NUM     compare mod-times with reduced accuracy\n");
328   rprintf(F," -T, --temp-dir=DIR          create temporary files in directory DIR\n");
329   rprintf(F," -y, --fuzzy                 find similar file for basis if no dest file\n");
330   rprintf(F,"     --compare-dest=DIR      also compare destination files relative to DIR\n");
331   rprintf(F,"     --copy-dest=DIR         ... and include copies of unchanged files\n");
332   rprintf(F,"     --link-dest=DIR         hardlink to files in DIR when unchanged\n");
333   rprintf(F," -z, --compress              compress file data during the transfer\n");
334   rprintf(F,"     --compress-level=NUM    explicitly set compression level\n");
335   rprintf(F," -C, --cvs-exclude           auto-ignore files the same way CVS does\n");
336   rprintf(F," -f, --filter=RULE           add a file-filtering RULE\n");
337   rprintf(F," -F                          same as --filter='dir-merge /.rsync-filter'\n");
338   rprintf(F,"                             repeated: --filter='- .rsync-filter'\n");
339   rprintf(F,"     --exclude=PATTERN       exclude files matching PATTERN\n");
340   rprintf(F,"     --exclude-from=FILE     read exclude patterns from FILE\n");
341   rprintf(F,"     --include=PATTERN       don't exclude files matching PATTERN\n");
342   rprintf(F,"     --include-from=FILE     read include patterns from FILE\n");
343   rprintf(F,"     --files-from=FILE       read list of source-file names from FILE\n");
344   rprintf(F," -0, --from0                 all *-from/filter files are delimited by 0s\n");
345   rprintf(F,"     --address=ADDRESS       bind address for outgoing socket to daemon\n");
346   rprintf(F,"     --port=PORT             specify double-colon alternate port number\n");
347   rprintf(F,"     --blocking-io           use blocking I/O for the remote shell\n");
348   rprintf(F,"     --stats                 give some file-transfer stats\n");
349   rprintf(F," -h, --human-readable        output numbers in a human-readable format\n");
350   rprintf(F,"     --si                    like human-readable, but use powers of 1000\n");
351   rprintf(F,"     --progress              show progress during transfer\n");
352   rprintf(F," -P                          same as --partial --progress\n");
353   rprintf(F," -i, --itemize-changes       output a change-summary for all updates\n");
354   rprintf(F,"     --log-format=FORMAT     output filenames using the specified format\n");
355   rprintf(F,"     --password-file=FILE    read password from FILE\n");
356   rprintf(F,"     --list-only             list the files instead of copying them\n");
357   rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth; KBytes per second\n");
358   rprintf(F,"     --write-batch=FILE      write a batched update to FILE\n");
359   rprintf(F,"     --only-write-batch=FILE like --write-batch but w/o updating destination\n");
360   rprintf(F,"     --read-batch=FILE       read a batched update from FILE\n");
361   rprintf(F,"     --protocol=NUM          force an older protocol version to be used\n");
362 #ifdef INET6
363   rprintf(F," -4, --ipv4                  prefer IPv4\n");
364   rprintf(F," -6, --ipv6                  prefer IPv6\n");
365 #endif
366   rprintf(F,"     --version               print version number\n");
367   rprintf(F,"     --help                  show this help screen\n");
368
369   rprintf(F,"\nUse \"rsync --daemon --help\" to see the daemon-mode command-line options.\n");
370   rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) man pages for full documentation.\n");
371   rprintf(F,"See http://rsync.samba.org/ for updates, bug reports, and answers\n");
372 }
373
374 enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
375       OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
376       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE,
377       OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
378       OPT_REFUSED_BASE = 9000};
379
380 static struct poptOption long_options[] = {
381   /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
382   {"help",             0,  POPT_ARG_NONE,   0, OPT_HELP, 0, 0 },
383   {"version",          0,  POPT_ARG_NONE,   0, OPT_VERSION, 0, 0},
384   {"verbose",         'v', POPT_ARG_NONE,   0, 'v', 0, 0 },
385   {"no-verbose",       0,  POPT_ARG_VAL,    &verbose, 0, 0, 0 },
386   {"no-v",             0,  POPT_ARG_VAL,    &verbose, 0, 0, 0 },
387   {"quiet",           'q', POPT_ARG_NONE,   0, 'q', 0, 0 },
388   {"stats",            0,  POPT_ARG_NONE,   &do_stats, 0, 0, 0 },
389   {"human-readable",  'h', POPT_ARG_VAL,    &human_readable, 1, 0, 0},
390   {"si",               0,  POPT_ARG_VAL,    &human_readable, 2, 0, 0},
391   {"dry-run",         'n', POPT_ARG_NONE,   &dry_run, 0, 0, 0 },
392   {"archive",         'a', POPT_ARG_NONE,   0, 'a', 0, 0 },
393   {"recursive",       'r', POPT_ARG_VAL,    &recurse, 2, 0, 0 },
394   {"no-recursive",     0,  POPT_ARG_VAL,    &recurse, 0, 0, 0 },
395   {"no-r",             0,  POPT_ARG_VAL,    &recurse, 0, 0, 0 },
396   {"dirs",            'd', POPT_ARG_VAL,    &xfer_dirs, 2, 0, 0 },
397   {"no-dirs",          0,  POPT_ARG_VAL,    &xfer_dirs, 0, 0, 0 },
398   {"no-d",             0,  POPT_ARG_VAL,    &xfer_dirs, 0, 0, 0 },
399   {"perms",           'p', POPT_ARG_VAL,    &preserve_perms, 1, 0, 0 },
400   {"no-perms",         0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
401   {"no-p",             0,  POPT_ARG_VAL,    &preserve_perms, 0, 0, 0 },
402   {"times",           't', POPT_ARG_VAL,    &preserve_times, 1, 0, 0 },
403   {"no-times",         0,  POPT_ARG_VAL,    &preserve_times, 0, 0, 0 },
404   {"no-t",             0,  POPT_ARG_VAL,    &preserve_times, 0, 0, 0 },
405   {"omit-dir-times",  'O', POPT_ARG_VAL,    &omit_dir_times, 2, 0, 0 },
406   {"modify-window",    0,  POPT_ARG_INT,    &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
407   {"owner",           'o', POPT_ARG_VAL,    &preserve_uid, 1, 0, 0 },
408   {"no-owner",         0,  POPT_ARG_VAL,    &preserve_uid, 0, 0, 0 },
409   {"no-o",             0,  POPT_ARG_VAL,    &preserve_uid, 0, 0, 0 },
410   {"group",           'g', POPT_ARG_VAL,    &preserve_gid, 1, 0, 0 },
411   {"no-group",         0,  POPT_ARG_VAL,    &preserve_gid, 0, 0, 0 },
412   {"no-g",             0,  POPT_ARG_VAL,    &preserve_gid, 0, 0, 0 },
413   {"devices",         'D', POPT_ARG_VAL,    &preserve_devices, 1, 0, 0 },
414   {"no-devices",       0,  POPT_ARG_VAL,    &preserve_devices, 0, 0, 0 },
415   {"no-D",             0,  POPT_ARG_VAL,    &preserve_devices, 0, 0, 0 },
416   {"links",           'l', POPT_ARG_VAL,    &preserve_links, 1, 0, 0 },
417   {"no-links",         0,  POPT_ARG_VAL,    &preserve_links, 0, 0, 0 },
418   {"no-l",             0,  POPT_ARG_VAL,    &preserve_links, 0, 0, 0 },
419   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links, 0, 0, 0 },
420   {"copy-unsafe-links",0,  POPT_ARG_NONE,   &copy_unsafe_links, 0, 0, 0 },
421   {"safe-links",       0,  POPT_ARG_NONE,   &safe_symlinks, 0, 0, 0 },
422   {"keep-dirlinks",   'K', POPT_ARG_NONE,   &keep_dirlinks, 0, 0, 0 },
423   {"hard-links",      'H', POPT_ARG_NONE,   &preserve_hard_links, 0, 0, 0 },
424   {"relative",        'R', POPT_ARG_VAL,    &relative_paths, 1, 0, 0 },
425   {"no-relative",      0,  POPT_ARG_VAL,    &relative_paths, 0, 0, 0 },
426   {"no-R",             0,  POPT_ARG_VAL,    &relative_paths, 0, 0, 0 },
427   {"no-implied-dirs",  0,  POPT_ARG_VAL,    &implied_dirs, 0, 0, 0 },
428   {"chmod",            0,  POPT_ARG_STRING, &chmod_mode, 0, 0, 0 },
429   {"ignore-times",    'I', POPT_ARG_NONE,   &ignore_times, 0, 0, 0 },
430   {"size-only",        0,  POPT_ARG_NONE,   &size_only, 0, 0, 0 },
431   {"one-file-system", 'x', POPT_ARG_NONE,   &one_file_system, 0, 0, 0 },
432   {"update",          'u', POPT_ARG_NONE,   &update_only, 0, 0, 0 },
433   {"existing",         0,  POPT_ARG_NONE,   &ignore_non_existing, 0, 0, 0 },
434   {"ignore-existing",  0,  POPT_ARG_NONE,   &ignore_existing, 0, 0, 0 },
435   {"ignore-non-existing",0,POPT_ARG_NONE,   &ignore_non_existing, 0, 0, 0 },
436   {"max-size",         0,  POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
437   {"min-size",         0,  POPT_ARG_STRING, &min_size_arg, OPT_MIN_SIZE, 0, 0 },
438   {"sparse",          'S', POPT_ARG_NONE,   &sparse_files, 0, 0, 0 },
439   {"inplace",          0,  POPT_ARG_NONE,   &inplace, 0, 0, 0 },
440   {"append",           0,  POPT_ARG_VAL,    &append_mode, 1, 0, 0 },
441   {"del",              0,  POPT_ARG_NONE,   &delete_during, 0, 0, 0 },
442   {"delete",           0,  POPT_ARG_NONE,   &delete_mode, 0, 0, 0 },
443   {"delete-before",    0,  POPT_ARG_VAL,    &delete_before, 2, 0, 0 },
444   {"delete-during",    0,  POPT_ARG_NONE,   &delete_during, 0, 0, 0 },
445   {"delete-after",     0,  POPT_ARG_NONE,   &delete_after, 0, 0, 0 },
446   {"delete-excluded",  0,  POPT_ARG_NONE,   &delete_excluded, 0, 0, 0 },
447   {"remove-sent-files",0,  POPT_ARG_NONE,   &remove_sent_files, 0, 0, 0 },
448   {"force",            0,  POPT_ARG_NONE,   &force_delete, 0, 0, 0 },
449   {"ignore-errors",    0,  POPT_ARG_NONE,   &ignore_errors, 0, 0, 0 },
450   {"max-delete",       0,  POPT_ARG_INT,    &max_delete, 0, 0, 0 },
451   {0,                 'F', POPT_ARG_NONE,   0, 'F', 0, 0 },
452   {"filter",          'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 },
453   {"exclude",          0,  POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
454   {"include",          0,  POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 },
455   {"exclude-from",     0,  POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 },
456   {"include-from",     0,  POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 },
457   {"cvs-exclude",     'C', POPT_ARG_NONE,   &cvs_exclude, 0, 0, 0 },
458   {"whole-file",      'W', POPT_ARG_VAL,    &whole_file, 1, 0, 0 },
459   {"no-whole-file",    0,  POPT_ARG_VAL,    &whole_file, 0, 0, 0 },
460   {"no-W",             0,  POPT_ARG_VAL,    &whole_file, 0, 0, 0 },
461   {"checksum",        'c', POPT_ARG_NONE,   &always_checksum, 0, 0, 0 },
462   {"block-size",      'B', POPT_ARG_LONG,   &block_size, 0, 0, 0 },
463   {"compare-dest",     0,  POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
464   {"copy-dest",        0,  POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
465   {"link-dest",        0,  POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 },
466   {"fuzzy",           'y', POPT_ARG_NONE,   &fuzzy_basis, 0, 0, 0 },
467   {"compress",        'z', POPT_ARG_NONE,   0, 'z', 0, 0 },
468   {"compress-level",   0,  POPT_ARG_INT,    &def_compress_level, 'z', 0, 0 },
469   {0,                 'P', POPT_ARG_NONE,   0, 'P', 0, 0 },
470   {"progress",         0,  POPT_ARG_VAL,    &do_progress, 1, 0, 0 },
471   {"no-progress",      0,  POPT_ARG_VAL,    &do_progress, 0, 0, 0 },
472   {"partial",          0,  POPT_ARG_VAL,    &keep_partial, 1, 0, 0 },
473   {"no-partial",       0,  POPT_ARG_VAL,    &keep_partial, 0, 0, 0 },
474   {"partial-dir",      0,  POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
475   {"delay-updates",    0,  POPT_ARG_NONE,   &delay_updates, 0, 0, 0 },
476   {"log-format",       0,  POPT_ARG_STRING, &log_format, 0, 0, 0 },
477   {"itemize-changes", 'i', POPT_ARG_NONE,   &itemize_changes, 0, 0, 0 },
478   {"bwlimit",          0,  POPT_ARG_INT,    &bwlimit, 0, 0, 0 },
479   {"backup",          'b', POPT_ARG_NONE,   &make_backups, 0, 0, 0 },
480   {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
481   {"suffix",           0,  POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
482   {"list-only",        0,  POPT_ARG_VAL,    &list_only, 2, 0, 0 },
483   {"read-batch",       0,  POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
484   {"write-batch",      0,  POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
485   {"only-write-batch", 0,  POPT_ARG_STRING, &batch_name, OPT_ONLY_WRITE_BATCH, 0, 0 },
486   {"files-from",       0,  POPT_ARG_STRING, &files_from, 0, 0, 0 },
487   {"from0",           '0', POPT_ARG_NONE,   &eol_nulls, 0, 0, 0},
488   {"numeric-ids",      0,  POPT_ARG_NONE,   &numeric_ids, 0, 0, 0 },
489   {"timeout",          0,  POPT_ARG_INT,    &io_timeout, 0, 0, 0 },
490   {"rsh",             'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
491   {"rsync-path",       0,  POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
492   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
493 #ifdef INET6
494   {"ipv4",            '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
495   {"ipv6",            '6', POPT_ARG_VAL,    &default_af_hint, AF_INET6, 0, 0 },
496 #endif
497   {"address",          0,  POPT_ARG_STRING, &bind_address, 0, 0, 0 },
498   {"port",             0,  POPT_ARG_INT,    &rsync_port, 0, 0, 0 },
499   {"password-file",    0,  POPT_ARG_STRING, &password_file, 0, 0, 0 },
500   {"blocking-io",      0,  POPT_ARG_VAL,    &blocking_io, 1, 0, 0 },
501   {"no-blocking-io",   0,  POPT_ARG_VAL,    &blocking_io, 0, 0, 0 },
502   {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
503   {"checksum-seed",    0,  POPT_ARG_INT,    &checksum_seed, 0, 0, 0 },
504   {"server",           0,  POPT_ARG_NONE,   &am_server, 0, 0, 0 },
505   {"sender",           0,  POPT_ARG_NONE,   0, OPT_SENDER, 0, 0 },
506   /* All the following options switch us into daemon-mode option-parsing. */
507   {"config",           0,  POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
508   {"daemon",           0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
509   {"detach",           0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
510   {"no-detach",        0,  POPT_ARG_NONE,   0, OPT_DAEMON, 0, 0 },
511   {0,0,0,0, 0, 0, 0}
512 };
513
514 static void daemon_usage(enum logcode F)
515 {
516   print_rsync_version(F);
517
518   rprintf(F,"\nUsage: rsync --daemon [OPTION]...\n");
519   rprintf(F,"     --address=ADDRESS       bind to the specified address\n");
520   rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth; KBytes per second\n");
521   rprintf(F,"     --config=FILE           specify alternate rsyncd.conf file\n");
522   rprintf(F,"     --no-detach             do not detach from the parent\n");
523   rprintf(F,"     --port=PORT             listen on alternate port number\n");
524   rprintf(F," -v, --verbose               increase verbosity\n");
525 #ifdef INET6
526   rprintf(F," -4, --ipv4                  prefer IPv4\n");
527   rprintf(F," -6, --ipv6                  prefer IPv6\n");
528 #endif
529   rprintf(F,"     --help                  show this help screen\n");
530
531   rprintf(F,"\nIf you were not trying to invoke rsync as a daemon, avoid using any of the\n");
532   rprintf(F,"daemon-specific rsync options.  See also the rsyncd.conf(5) man page.\n");
533 }
534
535 static struct poptOption long_daemon_options[] = {
536   /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
537   {"address",          0,  POPT_ARG_STRING, &bind_address, 0, 0, 0 },
538   {"bwlimit",          0,  POPT_ARG_INT,    &daemon_bwlimit, 0, 0, 0 },
539   {"config",           0,  POPT_ARG_STRING, &config_file, 0, 0, 0 },
540   {"daemon",           0,  POPT_ARG_NONE,   &daemon_opt, 0, 0, 0 },
541 #ifdef INET6
542   {"ipv4",            '4', POPT_ARG_VAL,    &default_af_hint, AF_INET, 0, 0 },
543   {"ipv6",            '6', POPT_ARG_VAL,    &default_af_hint, AF_INET6, 0, 0 },
544 #endif
545   {"detach",           0,  POPT_ARG_VAL,    &no_detach, 0, 0, 0 },
546   {"no-detach",        0,  POPT_ARG_VAL,    &no_detach, 1, 0, 0 },
547   {"port",             0,  POPT_ARG_INT,    &rsync_port, 0, 0, 0 },
548   {"protocol",         0,  POPT_ARG_INT,    &protocol_version, 0, 0, 0 },
549   {"server",           0,  POPT_ARG_NONE,   &am_server, 0, 0, 0 },
550   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
551   {"verbose",         'v', POPT_ARG_NONE,   0, 'v', 0, 0 },
552   {"no-verbose",       0,  POPT_ARG_VAL,    &verbose, 0, 0, 0 },
553   {"no-v",             0,  POPT_ARG_VAL,    &verbose, 0, 0, 0 },
554   {"help",            'h', POPT_ARG_NONE,   0, 'h', 0, 0 },
555   {0,0,0,0, 0, 0, 0}
556 };
557
558
559 static char err_buf[200];
560
561
562 /**
563  * Store the option error message, if any, so that we can log the
564  * connection attempt (which requires parsing the options), and then
565  * show the error later on.
566  **/
567 void option_error(void)
568 {
569         if (!err_buf[0]) {
570                 strcpy(err_buf, "Error parsing options: "
571                     "option may be supported on client but not on server?\n");
572         }
573
574         rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
575 }
576
577
578 /**
579  * Tweak the option table to disable all options that the rsyncd.conf
580  * file has told us to refuse.
581  **/
582 static void set_refuse_options(char *bp)
583 {
584         struct poptOption *op;
585         char *cp, shortname[2];
586         int is_wild, found_match;
587
588         shortname[1] = '\0';
589
590         while (1) {
591                 while (*bp == ' ') bp++;
592                 if (!*bp)
593                         break;
594                 if ((cp = strchr(bp, ' ')) != NULL)
595                         *cp= '\0';
596                 is_wild = strpbrk(bp, "*?[") != NULL;
597                 found_match = 0;
598                 for (op = long_options; ; op++) {
599                         *shortname = op->shortName;
600                         if (!op->longName && !*shortname)
601                                 break;
602                         if ((op->longName && wildmatch(bp, op->longName))
603                             || (*shortname && wildmatch(bp, shortname))) {
604                                 if (op->argInfo == POPT_ARG_VAL)
605                                         op->argInfo = POPT_ARG_NONE;
606                                 op->val = (op - long_options) + OPT_REFUSED_BASE;
607                                 found_match = 1;
608                                 /* These flags are set to let us easily check
609                                  * an implied option later in the code. */
610                                 switch (*shortname) {
611                                 case 'r': case 'd': case 'l': case 'p':
612                                 case 't': case 'g': case 'o': case 'D':
613                                         refused_archive_part = op->val;
614                                         break;
615                                 case 'z':
616                                         refused_compress = op->val;
617                                         break;
618                                 case '\0':
619                                         if (wildmatch("delete", op->longName))
620                                                 refused_delete = op->val;
621                                         else if (wildmatch("delete-before", op->longName))
622                                                 refused_delete_before = op->val;
623                                         else if (wildmatch("partial", op->longName))
624                                                 refused_partial = op->val;
625                                         else if (wildmatch("progress", op->longName))
626                                                 refused_progress = op->val;
627                                         else if (wildmatch("inplace", op->longName))
628                                                 refused_inplace = op->val;
629                                         break;
630                                 }
631                                 if (!is_wild)
632                                         break;
633                         }
634                 }
635                 if (!found_match) {
636                         rprintf(FLOG, "No match for refuse-options string \"%s\"\n",
637                                 bp);
638                 }
639                 if (!cp)
640                         break;
641                 *cp = ' ';
642                 bp = cp + 1;
643         }
644
645         for (op = long_options; ; op++) {
646                 *shortname = op->shortName;
647                 if (!op->longName && !*shortname)
648                         break;
649                 if (op->val == OPT_DAEMON) {
650                         if (op->argInfo == POPT_ARG_VAL)
651                                 op->argInfo = POPT_ARG_NONE;
652                         op->val = (op - long_options) + OPT_REFUSED_BASE;
653                 }
654         }
655 }
656
657
658 static int count_args(const char **argv)
659 {
660         int i = 0;
661
662         if (argv) {
663                 while (argv[i] != NULL)
664                         i++;
665         }
666
667         return i;
668 }
669
670
671 static OFF_T parse_size_arg(char **size_arg, char def_suf)
672 {
673         int mult, make_compatible = 0;
674         const char *arg, *p;
675         OFF_T size = 0;
676
677         for (arg = *size_arg; isdigit(*(uchar*)arg); arg++) {}
678         if (*arg == '.')
679                 for (arg++; isdigit(*(uchar*)arg); arg++) {}
680         if (*arg && (arg[1] == 'b' || arg[1] == 'B'))
681                 mult = 1000, make_compatible = 1;
682         else
683                 mult = 1024;
684         if ((p = strstr(arg, "+1")) != NULL
685          || (p = strstr(arg, "-1")) != NULL) {
686                 if (p[2] != '\0')
687                         return -1;
688                 size = atoi(p);
689                 make_compatible = 1;
690         }
691         switch (*arg && arg != p ? *arg : def_suf) {
692         case 'b': case 'B':
693                 size += atof(*size_arg);
694                 break;
695         case 'k': case 'K':
696                 size += atof(*size_arg) * mult;
697                 break;
698         case 'm': case 'M':
699                 size += atof(*size_arg) * mult*mult;
700                 break;
701         case 'g': case 'G':
702                 size += atof(*size_arg) * mult*mult*mult;
703                 break;
704         default:
705                 size = -1;
706                 break;
707         }
708         if (size > 0 && make_compatible) {
709                 /* We convert this manually because we may need %lld precision,
710                  * and that's not a portable sprintf() escape. */
711                 char buf[128], *s = buf + sizeof buf - 1;
712                 OFF_T num = size;
713                 *s = '\0';
714                 while (num) {
715                         *--s = (num % 10) + '0';
716                         num /= 10;
717                 }
718                 if (!(*size_arg = strdup(s)))
719                         out_of_memory("parse_size_arg");
720         }
721         return size;
722 }
723
724
725 static void create_refuse_error(int which)
726 {
727         /* The "which" value is the index + OPT_REFUSED_BASE. */
728         struct poptOption *op = &long_options[which - OPT_REFUSED_BASE];
729         int n = snprintf(err_buf, sizeof err_buf,
730                          "The server is configured to refuse --%s\n",
731                          op->longName) - 1;
732         if (op->shortName) {
733                 snprintf(err_buf + n, sizeof err_buf - n,
734                          " (-%c)\n", op->shortName);
735         }
736 }
737
738
739 /**
740  * Process command line arguments.  Called on both local and remote.
741  *
742  * @retval 1 if all options are OK; with globals set to appropriate
743  * values
744  *
745  * @retval 0 on error, with err_buf containing an explanation
746  **/
747 int parse_arguments(int *argc, const char ***argv, int frommain)
748 {
749         int opt;
750         char *ref = lp_refuse_options(module_id);
751         const char *arg;
752         poptContext pc;
753
754         if (ref && *ref)
755                 set_refuse_options(ref);
756
757         /* TODO: Call poptReadDefaultConfig; handle errors. */
758
759         /* The context leaks in case of an error, but if there's a
760          * problem we always exit anyhow. */
761         pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
762         poptReadDefaultConfig(pc, 0);
763
764         while ((opt = poptGetNextOpt(pc)) != -1) {
765                 /* most options are handled automatically by popt;
766                  * only special cases are returned and listed here. */
767
768                 switch (opt) {
769                 case OPT_VERSION:
770                         print_rsync_version(FINFO);
771                         exit_cleanup(0);
772
773                 case OPT_DAEMON:
774                         if (am_daemon) {
775                                 strcpy(err_buf, "Attempt to hack rsync thwarted!\n");
776                                 return 0;
777                         }
778                         poptFreeContext(pc);
779                         pc = poptGetContext(RSYNC_NAME, *argc, *argv,
780                                             long_daemon_options, 0);
781                         while ((opt = poptGetNextOpt(pc)) != -1) {
782                                 switch (opt) {
783                                 case 'h':
784                                         daemon_usage(FINFO);
785                                         exit_cleanup(0);
786
787                                 case 'v':
788                                         verbose++;
789                                         break;
790
791                                 default:
792                                         rprintf(FERROR,
793                                             "rsync: %s: %s (in daemon mode)\n",
794                                             poptBadOption(pc, POPT_BADOPTION_NOALIAS),
795                                             poptStrerror(opt));
796                                         goto daemon_error;
797                                 }
798                         }
799
800                         if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
801                                 snprintf(err_buf, sizeof err_buf,
802                                          "the --temp-dir path is WAY too long.\n");
803                                 return 0;
804                         }
805
806                         if (!daemon_opt) {
807                                 rprintf(FERROR, "Daemon option(s) used without --daemon.\n");
808                             daemon_error:
809                                 rprintf(FERROR,
810                                     "(Type \"rsync --daemon --help\" for assistance with daemon mode.)\n");
811                                 exit_cleanup(RERR_SYNTAX);
812                         }
813
814                         *argv = poptGetArgs(pc);
815                         *argc = count_args(*argv);
816                         am_starting_up = 0;
817                         daemon_opt = 0;
818                         am_daemon = 1;
819                         return 1;
820
821                 case OPT_MODIFY_WINDOW:
822                         /* The value has already been set by popt, but
823                          * we need to remember that we're using a
824                          * non-default setting. */
825                         modify_window_set = 1;
826                         break;
827
828                 case OPT_FILTER:
829                         parse_rule(&filter_list, poptGetOptArg(pc), 0, 0);
830                         break;
831
832                 case OPT_EXCLUDE:
833                         parse_rule(&filter_list, poptGetOptArg(pc),
834                                    0, XFLG_OLD_PREFIXES);
835                         break;
836
837                 case OPT_INCLUDE:
838                         parse_rule(&filter_list, poptGetOptArg(pc),
839                                    MATCHFLG_INCLUDE, XFLG_OLD_PREFIXES);
840                         break;
841
842                 case OPT_EXCLUDE_FROM:
843                 case OPT_INCLUDE_FROM:
844                         arg = poptGetOptArg(pc);
845                         if (sanitize_paths)
846                                 arg = sanitize_path(NULL, arg, NULL, 0);
847                         if (server_filter_list.head) {
848                                 char *cp = (char *)arg;
849                                 if (!*cp)
850                                         goto options_rejected;
851                                 clean_fname(cp, 1);
852                                 if (check_filter(&server_filter_list, cp, 0) < 0)
853                                         goto options_rejected;
854                         }
855                         parse_filter_file(&filter_list, arg,
856                                 opt == OPT_INCLUDE_FROM ? MATCHFLG_INCLUDE : 0,
857                                 XFLG_FATAL_ERRORS | XFLG_OLD_PREFIXES);
858                         break;
859
860                 case 'a':
861                         if (refused_archive_part) {
862                                 create_refuse_error(refused_archive_part);
863                                 return 0;
864                         }
865                         if (!recurse) /* preserve recurse == 2 */
866                                 recurse = 1;
867 #ifdef SUPPORT_LINKS
868                         preserve_links = 1;
869 #endif
870                         preserve_perms = 1;
871                         preserve_times = 1;
872                         preserve_gid = 1;
873                         preserve_uid = 1;
874                         preserve_devices = 1;
875                         break;
876
877                 case OPT_HELP:
878                         usage(FINFO);
879                         exit_cleanup(0);
880
881                 case 'v':
882                         verbose++;
883                         break;
884
885                 case 'q':
886                         if (frommain)
887                                 quiet++;
888                         break;
889
890                 case OPT_SENDER:
891                         if (!am_server) {
892                                 usage(FERROR);
893                                 exit_cleanup(RERR_SYNTAX);
894                         }
895                         am_sender = 1;
896                         break;
897
898                 case 'F':
899                         switch (++F_option_cnt) {
900                         case 1:
901                                 parse_rule(&filter_list,": /.rsync-filter",0,0);
902                                 break;
903                         case 2:
904                                 parse_rule(&filter_list,"- .rsync-filter",0,0);
905                                 break;
906                         }
907                         break;
908
909                 case 'P':
910                         if (refused_partial || refused_progress) {
911                                 create_refuse_error(refused_partial
912                                     ? refused_partial : refused_progress);
913                                 return 0;
914                         }
915                         do_progress = 1;
916                         keep_partial = 1;
917                         break;
918
919                 case 'z':
920                         if (def_compress_level < Z_DEFAULT_COMPRESSION
921                          || def_compress_level > Z_BEST_COMPRESSION) {
922                                 snprintf(err_buf, sizeof err_buf,
923                                         "--compress-level value is invalid: %d\n",
924                                         def_compress_level);
925                                 return 0;
926                         }
927                         do_compression = def_compress_level != Z_NO_COMPRESSION;
928                         if (do_compression && refused_compress) {
929                                 create_refuse_error(refused_compress);
930                                 return 0;
931                         }
932                         break;
933
934                 case OPT_WRITE_BATCH:
935                         /* batch_name is already set */
936                         write_batch = 1;
937                         break;
938
939                 case OPT_ONLY_WRITE_BATCH:
940                         /* batch_name is already set */
941                         write_batch = -1;
942                         break;
943
944                 case OPT_READ_BATCH:
945                         /* batch_name is already set */
946                         read_batch = 1;
947                         break;
948
949                 case OPT_MAX_SIZE:
950                         if ((max_size = parse_size_arg(&max_size_arg, 'b')) <= 0) {
951                                 snprintf(err_buf, sizeof err_buf,
952                                         "--max-size value is invalid: %s\n",
953                                         max_size_arg);
954                                 return 0;
955                         }
956                         break;
957
958                 case OPT_MIN_SIZE:
959                         if ((min_size = parse_size_arg(&min_size_arg, 'b')) <= 0) {
960                                 snprintf(err_buf, sizeof err_buf,
961                                         "--min-size value is invalid: %s\n",
962                                         min_size_arg);
963                                 return 0;
964                         }
965                         break;
966
967                 case OPT_LINK_DEST:
968 #ifdef HAVE_LINK
969                         link_dest = 1;
970                         dest_option = "--link-dest";
971                         goto set_dest_dir;
972 #else
973                         snprintf(err_buf, sizeof err_buf,
974                                  "hard links are not supported on this %s\n",
975                                  am_server ? "server" : "client");
976                         return 0;
977 #endif
978
979                 case OPT_COPY_DEST:
980                         copy_dest = 1;
981                         dest_option = "--copy-dest";
982                         goto set_dest_dir;
983
984                 case OPT_COMPARE_DEST:
985                         compare_dest = 1;
986                         dest_option = "--compare-dest";
987                 set_dest_dir:
988                         if (basis_dir_cnt >= MAX_BASIS_DIRS) {
989                                 snprintf(err_buf, sizeof err_buf,
990                                         "ERROR: at most %d %s args may be specified\n",
991                                         MAX_BASIS_DIRS, dest_option);
992                                 return 0;
993                         }
994                         arg = poptGetOptArg(pc);
995                         if (sanitize_paths)
996                                 arg = sanitize_path(NULL, arg, NULL, 0);
997                         basis_dir[basis_dir_cnt++] = (char *)arg;
998                         break;
999
1000                 default:
1001                         /* A large opt value means that set_refuse_options()
1002                          * turned this option off. */
1003                         if (opt >= OPT_REFUSED_BASE) {
1004                                 create_refuse_error(opt);
1005                                 return 0;
1006                         }
1007                         snprintf(err_buf, sizeof err_buf, "%s%s: %s\n",
1008                                  am_server ? "on remote machine: " : "",
1009                                  poptBadOption(pc, POPT_BADOPTION_NOALIAS),
1010                                  poptStrerror(opt));
1011                         return 0;
1012                 }
1013         }
1014
1015         if (human_readable && *argc == 2) {
1016                 usage(FINFO);
1017                 exit_cleanup(0);
1018         }
1019
1020 #ifndef SUPPORT_LINKS
1021         if (preserve_links && !am_sender) {
1022                 snprintf(err_buf, sizeof err_buf,
1023                          "symlinks are not supported on this %s\n",
1024                          am_server ? "server" : "client");
1025                 return 0;
1026         }
1027 #endif
1028
1029 #ifndef SUPPORT_HARD_LINKS
1030         if (preserve_hard_links) {
1031                 snprintf(err_buf, sizeof err_buf,
1032                          "hard links are not supported on this %s\n",
1033                          am_server ? "server" : "client");
1034                 return 0;
1035         }
1036 #endif
1037
1038         if (write_batch && read_batch) {
1039                 snprintf(err_buf, sizeof err_buf,
1040                         "--write-batch and --read-batch can not be used together\n");
1041                 return 0;
1042         }
1043         if (write_batch > 0 || read_batch) {
1044                 if (am_server) {
1045                         rprintf(FINFO,
1046                                 "ignoring --%s-batch option sent to server\n",
1047                                 write_batch ? "write" : "read");
1048                         /* We don't actually exit_cleanup(), so that we can
1049                          * still service older version clients that still send
1050                          * batch args to server. */
1051                         read_batch = write_batch = 0;
1052                         batch_name = NULL;
1053                 } else if (dry_run)
1054                         write_batch = 0;
1055         }
1056         if (read_batch && files_from) {
1057                 snprintf(err_buf, sizeof err_buf,
1058                         "--read-batch cannot be used with --files-from\n");
1059                 return 0;
1060         }
1061         if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
1062                 snprintf(err_buf, sizeof err_buf,
1063                         "the batch-file name must be %d characters or less.\n",
1064                         MAX_BATCH_NAME_LEN);
1065                 return 0;
1066         }
1067
1068         if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
1069                 snprintf(err_buf, sizeof err_buf,
1070                          "the --temp-dir path is WAY too long.\n");
1071                 return 0;
1072         }
1073
1074         if (compare_dest + copy_dest + link_dest > 1) {
1075                 snprintf(err_buf, sizeof err_buf,
1076                         "You may not mix --compare-dest, --copy-dest, and --link-dest.\n");
1077                 return 0;
1078         }
1079
1080         if (files_from) {
1081                 if (recurse == 1) /* preserve recurse == 2 */
1082                         recurse = 0;
1083                 if (xfer_dirs < 0)
1084                         xfer_dirs = 1;
1085         }
1086
1087         if (xfer_dirs < 1)
1088                 xfer_dirs = recurse || list_only;
1089
1090         if (relative_paths < 0)
1091                 relative_paths = files_from? 1 : 0;
1092         if (!relative_paths)
1093                 implied_dirs = 0;
1094
1095         if (!!delete_before + delete_during + delete_after > 1) {
1096                 snprintf(err_buf, sizeof err_buf,
1097                         "You may not combine multiple --delete-WHEN options.\n");
1098                 return 0;
1099         }
1100         if (!xfer_dirs) {
1101                 delete_before = delete_during = delete_after = 0;
1102                 delete_mode = delete_excluded = 0;
1103         } else if (delete_before || delete_during || delete_after)
1104                 delete_mode = 1;
1105         else if (delete_mode || delete_excluded) {
1106                 if (refused_delete_before) {
1107                         create_refuse_error(refused_delete_before);
1108                         return 0;
1109                 }
1110                 delete_mode = delete_before = 1;
1111         }
1112
1113         if (delete_mode && refused_delete) {
1114                 create_refuse_error(refused_delete);
1115                 return 0;
1116         }
1117
1118         if (remove_sent_files) {
1119                 /* We only want to infer this refusal of --remove-sent-files
1120                  * via the refusal of "delete", not any of the "delete-FOO"
1121                  * options. */
1122                 if (refused_delete && am_sender) {
1123                         create_refuse_error(refused_delete);
1124                         return 0;
1125                 }
1126                 need_messages_from_generator = 1;
1127         }
1128
1129         *argv = poptGetArgs(pc);
1130         *argc = count_args(*argv);
1131
1132         if (sanitize_paths) {
1133                 int i;
1134                 for (i = *argc; i-- > 0; )
1135                         (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0);
1136                 if (tmpdir)
1137                         tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
1138                 if (partial_dir)
1139                         partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
1140                 if (backup_dir)
1141                         backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
1142         }
1143         if (server_filter_list.head && !am_sender) {
1144                 struct filter_list_struct *elp = &server_filter_list;
1145                 int i;
1146                 if (tmpdir) {
1147                         if (!*tmpdir)
1148                                 goto options_rejected;
1149                         clean_fname(tmpdir, 1);
1150                         if (check_filter(elp, tmpdir, 1) < 0)
1151                                 goto options_rejected;
1152                 }
1153                 if (partial_dir && *partial_dir) {
1154                         clean_fname(partial_dir, 1);
1155                         if (check_filter(elp, partial_dir, 1) < 0)
1156                                 goto options_rejected;
1157                 }
1158                 for (i = 0; i < basis_dir_cnt; i++) {
1159                         if (!*basis_dir[i])
1160                                 goto options_rejected;
1161                         clean_fname(basis_dir[i], 1);
1162                         if (check_filter(elp, basis_dir[i], 1) < 0)
1163                                 goto options_rejected;
1164                 }
1165                 if (backup_dir) {
1166                         if (!*backup_dir)
1167                                 goto options_rejected;
1168                         clean_fname(backup_dir, 1);
1169                         if (check_filter(elp, backup_dir, 1) < 0) {
1170                             options_rejected:
1171                                 snprintf(err_buf, sizeof err_buf,
1172                                     "Your options have been rejected by the server.\n");
1173                                 return 0;
1174                         }
1175                 }
1176         }
1177
1178         if (!backup_suffix)
1179                 backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
1180         backup_suffix_len = strlen(backup_suffix);
1181         if (strchr(backup_suffix, '/') != NULL) {
1182                 snprintf(err_buf, sizeof err_buf,
1183                         "--suffix cannot contain slashes: %s\n",
1184                         backup_suffix);
1185                 return 0;
1186         }
1187         if (backup_dir) {
1188                 backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
1189                 backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
1190                 if (backup_dir_remainder < 32) {
1191                         snprintf(err_buf, sizeof err_buf,
1192                                 "the --backup-dir path is WAY too long.\n");
1193                         return 0;
1194                 }
1195                 if (backup_dir_buf[backup_dir_len - 1] != '/') {
1196                         backup_dir_buf[backup_dir_len++] = '/';
1197                         backup_dir_buf[backup_dir_len] = '\0';
1198                 }
1199                 if (verbose > 1 && !am_sender) {
1200                         rprintf(FINFO, "backup_dir is %s\n",
1201                                 safe_fname(backup_dir_buf));
1202                 }
1203         } else if (!backup_suffix_len && (!am_server || !am_sender)) {
1204                 snprintf(err_buf, sizeof err_buf,
1205                         "--suffix cannot be a null string without --backup-dir\n");
1206                 return 0;
1207         }
1208         if (make_backups && !backup_dir)
1209                 omit_dir_times = 1;
1210
1211         if (chmod_mode && !(chmod_modes = parse_chmod(chmod_mode))) {
1212                 snprintf(err_buf, sizeof err_buf,
1213                     "Invalid argument passed to chmod\n");
1214                 return 0;
1215         }
1216
1217         if (log_format) {
1218                 if (log_format_has(log_format, 'i'))
1219                         log_format_has_i = 1;
1220                 if (!log_format_has(log_format, 'b')
1221                  && !log_format_has(log_format, 'c'))
1222                         log_before_transfer = !am_server;
1223         } else if (itemize_changes) {
1224                 log_format = "%i %n%L";
1225                 log_format_has_i = 1;
1226                 log_before_transfer = !am_server;
1227         }
1228
1229         if ((do_progress || dry_run) && !verbose && !log_before_transfer
1230             && !am_server)
1231                 verbose = 1;
1232
1233         if (dry_run)
1234                 do_xfers = 0;
1235
1236         set_io_timeout(io_timeout);
1237
1238         if (verbose && !log_format) {
1239                 log_format = "%n%L";
1240                 log_before_transfer = !am_server;
1241         }
1242         if (log_format_has_i || log_format_has(log_format, 'o'))
1243                 log_format_has_o_or_i = 1;
1244
1245         if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit))
1246                 bwlimit = daemon_bwlimit;
1247         if (bwlimit) {
1248                 bwlimit_writemax = (size_t)bwlimit * 128;
1249                 if (bwlimit_writemax < 512)
1250                         bwlimit_writemax = 512;
1251         }
1252
1253         if (sparse_files && inplace) {
1254                 /* Note: we don't check for this below, because --append is
1255                  * OK with --sparse (as long as redos are handled right). */
1256                 snprintf(err_buf, sizeof err_buf,
1257                          "--sparse cannot be used with --inplace\n");
1258                 return 0;
1259         }
1260
1261         if (append_mode) {
1262                 if (whole_file > 0) {
1263                         snprintf(err_buf, sizeof err_buf,
1264                                  "--append cannot be used with --whole-file\n");
1265                         return 0;
1266                 }
1267                 if (refused_inplace) {
1268                         create_refuse_error(refused_inplace);
1269                         return 0;
1270                 }
1271                 inplace = 1;
1272         }
1273
1274         if (delay_updates && !partial_dir)
1275                 partial_dir = partialdir_for_delayupdate;
1276
1277         if (inplace) {
1278 #ifdef HAVE_FTRUNCATE
1279                 if (partial_dir) {
1280                         snprintf(err_buf, sizeof err_buf,
1281                                  "--%s cannot be used with --%s\n",
1282                                  append_mode ? "append" : "inplace",
1283                                  delay_updates ? "delay-updates" : "partial-dir");
1284                         return 0;
1285                 }
1286                 /* --inplace implies --partial for refusal purposes, but we
1287                  * clear the keep_partial flag for internal logic purposes. */
1288                 if (refused_partial) {
1289                         create_refuse_error(refused_partial);
1290                         return 0;
1291                 }
1292                 keep_partial = 0;
1293 #else
1294                 snprintf(err_buf, sizeof err_buf,
1295                          "--%s is not supported on this %s\n",
1296                          append_mode ? "append" : "inplace",
1297                          am_server ? "server" : "client");
1298                 return 0;
1299 #endif
1300         } else {
1301                 if (keep_partial && !partial_dir) {
1302                         if ((arg = getenv("RSYNC_PARTIAL_DIR")) != NULL && *arg)
1303                                 partial_dir = strdup(arg);
1304                 }
1305                 if (partial_dir) {
1306                         if (*partial_dir)
1307                                 clean_fname(partial_dir, 1);
1308                         if (!*partial_dir || strcmp(partial_dir, ".") == 0)
1309                                 partial_dir = NULL;
1310                         else if (*partial_dir != '/') {
1311                                 parse_rule(&filter_list, partial_dir,
1312                                     MATCHFLG_NO_PREFIXES|MATCHFLG_DIRECTORY, 0);
1313                         }
1314                         if (!partial_dir && refused_partial) {
1315                                 create_refuse_error(refused_partial);
1316                                 return 0;
1317                         }
1318                         keep_partial = 1;
1319                 }
1320         }
1321
1322         if (files_from) {
1323                 char *h, *p;
1324                 int q;
1325                 if (*argc > 2 || (!am_daemon && *argc == 1)) {
1326                         usage(FERROR);
1327                         exit_cleanup(RERR_SYNTAX);
1328                 }
1329                 if (strcmp(files_from, "-") == 0) {
1330                         filesfrom_fd = 0;
1331                         if (am_server)
1332                                 filesfrom_host = ""; /* reading from socket */
1333                 } else if ((p = check_for_hostspec(files_from, &h, &q)) != 0) {
1334                         if (am_server) {
1335                                 snprintf(err_buf, sizeof err_buf,
1336                                         "The --files-from sent to the server cannot specify a host.\n");
1337                                 return 0;
1338                         }
1339                         files_from = p;
1340                         filesfrom_host = h;
1341                         if (strcmp(files_from, "-") == 0) {
1342                                 snprintf(err_buf, sizeof err_buf,
1343                                         "Invalid --files-from remote filename\n");
1344                                 return 0;
1345                         }
1346                 } else {
1347                         if (sanitize_paths)
1348                                 files_from = sanitize_path(NULL, files_from, NULL, 0);
1349                         if (server_filter_list.head) {
1350                                 if (!*files_from)
1351                                         goto options_rejected;
1352                                 clean_fname(files_from, 1);
1353                                 if (check_filter(&server_filter_list, files_from, 0) < 0)
1354                                         goto options_rejected;
1355                         }
1356                         filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
1357                         if (filesfrom_fd < 0) {
1358                                 snprintf(err_buf, sizeof err_buf,
1359                                         "failed to open files-from file %s: %s\n",
1360                                         files_from, strerror(errno));
1361                                 return 0;
1362                         }
1363                 }
1364         }
1365
1366         am_starting_up = 0;
1367
1368         return 1;
1369 }
1370
1371
1372 /**
1373  * Construct a filtered list of options to pass through from the
1374  * client to the server.
1375  *
1376  * This involves setting options that will tell the server how to
1377  * behave, and also filtering out options that are processed only
1378  * locally.
1379  **/
1380 void server_options(char **args,int *argc)
1381 {
1382         static char argstr[64];
1383         int ac = *argc;
1384         char *arg;
1385
1386         int i, x;
1387
1388         if (blocking_io == -1)
1389                 blocking_io = 0;
1390
1391         args[ac++] = "--server";
1392
1393         if (daemon_over_rsh) {
1394                 args[ac++] = "--daemon";
1395                 *argc = ac;
1396                 /* if we're passing --daemon, we're done */
1397                 return;
1398         }
1399
1400         if (!am_sender)
1401                 args[ac++] = "--sender";
1402
1403         x = 1;
1404         argstr[0] = '-';
1405         for (i = 0; i < verbose; i++)
1406                 argstr[x++] = 'v';
1407
1408         /* the -q option is intentionally left out */
1409         if (make_backups)
1410                 argstr[x++] = 'b';
1411         if (update_only)
1412                 argstr[x++] = 'u';
1413         if (!do_xfers) /* NOT "dry_run"! */
1414                 argstr[x++] = 'n';
1415         if (preserve_links)
1416                 argstr[x++] = 'l';
1417         if (copy_links)
1418                 argstr[x++] = 'L';
1419         if (xfer_dirs > 1)
1420                 argstr[x++] = 'd';
1421         if (keep_dirlinks && am_sender)
1422                 argstr[x++] = 'K';
1423
1424         if (whole_file > 0)
1425                 argstr[x++] = 'W';
1426         /* We don't need to send --no-whole-file, because it's the
1427          * default for remote transfers, and in any case old versions
1428          * of rsync will not understand it. */
1429
1430         if (preserve_hard_links)
1431                 argstr[x++] = 'H';
1432         if (preserve_uid)
1433                 argstr[x++] = 'o';
1434         if (preserve_gid)
1435                 argstr[x++] = 'g';
1436         if (preserve_devices)
1437                 argstr[x++] = 'D';
1438         if (preserve_times)
1439                 argstr[x++] = 't';
1440         if (omit_dir_times == 2 && am_sender)
1441                 argstr[x++] = 'O';
1442         if (preserve_perms)
1443                 argstr[x++] = 'p';
1444         if (recurse)
1445                 argstr[x++] = 'r';
1446         if (always_checksum)
1447                 argstr[x++] = 'c';
1448         if (cvs_exclude)
1449                 argstr[x++] = 'C';
1450         if (ignore_times)
1451                 argstr[x++] = 'I';
1452         if (relative_paths)
1453                 argstr[x++] = 'R';
1454         if (one_file_system)
1455                 argstr[x++] = 'x';
1456         if (sparse_files)
1457                 argstr[x++] = 'S';
1458         if (do_compression)
1459                 argstr[x++] = 'z';
1460
1461         /* This is a complete hack - blame Rusty.  FIXME!
1462          * This hack is only needed for older rsync versions that
1463          * don't understand the --list-only option. */
1464         if (list_only == 1 && !recurse)
1465                 argstr[x++] = 'r';
1466
1467         argstr[x] = 0;
1468
1469         if (x != 1)
1470                 args[ac++] = argstr;
1471
1472         if (list_only > 1)
1473                 args[ac++] = "--list-only";
1474
1475         if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) {
1476                 if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0)
1477                         goto oom;
1478                 args[ac++] = arg;
1479         }
1480
1481         /* The server side doesn't use our log-format, but in certain
1482          * circumstances they need to know a little about the option. */
1483         if (log_format && am_sender) {
1484                 if (log_format_has_i)
1485                         args[ac++] = "--log-format=%i";
1486                 else if (log_format_has_o_or_i)
1487                         args[ac++] = "--log-format=%o";
1488                 else if (!verbose)
1489                         args[ac++] = "--log-format=X";
1490         }
1491
1492         if (block_size) {
1493                 if (asprintf(&arg, "-B%lu", block_size) < 0)
1494                         goto oom;
1495                 args[ac++] = arg;
1496         }
1497
1498         if (max_delete && am_sender) {
1499                 if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
1500                         goto oom;
1501                 args[ac++] = arg;
1502         }
1503
1504         if (min_size && am_sender) {
1505                 args[ac++] = "--min-size";
1506                 args[ac++] = min_size_arg;
1507         }
1508
1509         if (max_size && am_sender) {
1510                 args[ac++] = "--max-size";
1511                 args[ac++] = max_size_arg;
1512         }
1513
1514         if (io_timeout) {
1515                 if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
1516                         goto oom;
1517                 args[ac++] = arg;
1518         }
1519
1520         if (bwlimit) {
1521                 if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0)
1522                         goto oom;
1523                 args[ac++] = arg;
1524         }
1525
1526         if (backup_dir) {
1527                 args[ac++] = "--backup-dir";
1528                 args[ac++] = backup_dir;
1529         }
1530
1531         /* Only send --suffix if it specifies a non-default value. */
1532         if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
1533                 /* We use the following syntax to avoid weirdness with '~'. */
1534                 if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
1535                         goto oom;
1536                 args[ac++] = arg;
1537         }
1538
1539         if (am_sender) {
1540                 if (delete_excluded)
1541                         args[ac++] = "--delete-excluded";
1542                 else if (delete_before == 1 || delete_after)
1543                         args[ac++] = "--delete";
1544                 if (delete_before > 1)
1545                         args[ac++] = "--delete-before";
1546                 if (delete_during)
1547                         args[ac++] = "--delete-during";
1548                 if (delete_after)
1549                         args[ac++] = "--delete-after";
1550                 if (force_delete)
1551                         args[ac++] = "--force";
1552                 if (write_batch < 0)
1553                         args[ac++] = "--only-write-batch=X";
1554         }
1555
1556         if (size_only)
1557                 args[ac++] = "--size-only";
1558
1559         if (modify_window_set) {
1560                 if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
1561                         goto oom;
1562                 args[ac++] = arg;
1563         }
1564
1565         if (checksum_seed) {
1566                 if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
1567                         goto oom;
1568                 args[ac++] = arg;
1569         }
1570
1571         if (partial_dir && am_sender) {
1572                 if (partial_dir != partialdir_for_delayupdate) {
1573                         args[ac++] = "--partial-dir";
1574                         args[ac++] = partial_dir;
1575                 }
1576                 if (delay_updates)
1577                         args[ac++] = "--delay-updates";
1578         } else if (keep_partial)
1579                 args[ac++] = "--partial";
1580
1581         if (ignore_errors)
1582                 args[ac++] = "--ignore-errors";
1583
1584         if (copy_unsafe_links)
1585                 args[ac++] = "--copy-unsafe-links";
1586
1587         if (safe_symlinks)
1588                 args[ac++] = "--safe-links";
1589
1590         if (numeric_ids)
1591                 args[ac++] = "--numeric-ids";
1592
1593         if (ignore_existing && am_sender)
1594                 args[ac++] = "--ignore-existing";
1595
1596         /* Backward compatibility: send --existing, not --ignore-non-existing. */
1597         if (ignore_non_existing && am_sender)
1598                 args[ac++] = "--existing";
1599
1600         if (append_mode)
1601                 args[ac++] = "--append";
1602         else if (inplace)
1603                 args[ac++] = "--inplace";
1604
1605         if (tmpdir) {
1606                 args[ac++] = "--temp-dir";
1607                 args[ac++] = tmpdir;
1608         }
1609
1610         if (basis_dir[0] && am_sender) {
1611                 /* the server only needs this option if it is not the sender,
1612                  *   and it may be an older version that doesn't know this
1613                  *   option, so don't send it if client is the sender.
1614                  */
1615                 int i;
1616                 for (i = 0; i < basis_dir_cnt; i++) {
1617                         args[ac++] = dest_option;
1618                         args[ac++] = basis_dir[i];
1619                 }
1620         }
1621
1622         if (chmod_mode && !am_sender) {
1623                 args[ac++] = "--chmod";
1624                 args[ac++] = chmod_mode;
1625         }
1626
1627         if (files_from && (!am_sender || filesfrom_host)) {
1628                 if (filesfrom_host) {
1629                         args[ac++] = "--files-from";
1630                         args[ac++] = files_from;
1631                         if (eol_nulls)
1632                                 args[ac++] = "--from0";
1633                 } else {
1634                         args[ac++] = "--files-from=-";
1635                         args[ac++] = "--from0";
1636                 }
1637                 if (!relative_paths)
1638                         args[ac++] = "--no-relative";
1639         }
1640         if (relative_paths && !implied_dirs && !am_sender)
1641                 args[ac++] = "--no-implied-dirs";
1642
1643         if (fuzzy_basis && am_sender)
1644                 args[ac++] = "--fuzzy";
1645
1646         if (remove_sent_files)
1647                 args[ac++] = "--remove-sent-files";
1648
1649         *argc = ac;
1650         return;
1651
1652     oom:
1653         out_of_memory("server_options");
1654 }
1655
1656 /* Look for a HOST specfication of the form "HOST:PATH", "HOST::PATH", or
1657  * "rsync://HOST:PORT/PATH".  If found, *host_ptr will be set to some allocated
1658  * memory with the HOST.  If a daemon-accessing spec was specified, the value
1659  * of *port_ptr will contain a non-0 port number, otherwise it will be set to
1660  * 0.  The return value is a pointer to the PATH.  Note that the HOST spec can
1661  * be an IPv6 literal address enclosed in '[' and ']' (such as "[::1]" or
1662  * "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */
1663 char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr)
1664 {
1665         char *p;
1666         int not_host;
1667
1668         if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) {
1669                 char *path;
1670                 int hostlen;
1671                 s += strlen(URL_PREFIX);
1672                 if ((p = strchr(s, '/')) != NULL) {
1673                         hostlen = p - s;
1674                         path = p + 1;
1675                 } else {
1676                         hostlen = strlen(s);
1677                         path = "";
1678                 }
1679                 if (*s == '[' && (p = strchr(s, ']')) != NULL) {
1680                         s++;
1681                         hostlen = p - s;
1682                         if (p[1] == ':')
1683                                 *port_ptr = atoi(p+2);
1684                 } else {
1685                         if ((p = strchr(s, ':')) != NULL) {
1686                                 hostlen = p - s;
1687                                 *port_ptr = atoi(p+1);
1688                         }
1689                 }
1690                 if (!*port_ptr)
1691                         *port_ptr = RSYNC_PORT;
1692                 *host_ptr = new_array(char, hostlen + 1);
1693                 strlcpy(*host_ptr, s, hostlen + 1);
1694                 return path;
1695         }
1696
1697         if (*s == '[' && (p = strchr(s, ']')) != NULL && p[1] == ':') {
1698                 s++;
1699                 *p = '\0';
1700                 not_host = strchr(s, '/') || !strchr(s, ':');
1701                 *p = ']';
1702                 if (not_host)
1703                         return NULL;
1704                 p++;
1705         } else {
1706                 if (!(p = strchr(s, ':')))
1707                         return NULL;
1708                 *p = '\0';
1709                 not_host = strchr(s, '/') != NULL;
1710                 *p = ':';
1711                 if (not_host)
1712                         return NULL;
1713         }
1714
1715         *host_ptr = new_array(char, p - s + 1);
1716         strlcpy(*host_ptr, s, p - s + 1);
1717
1718         if (p[1] == ':') {
1719                 if (port_ptr && !*port_ptr)
1720                         *port_ptr = RSYNC_PORT;
1721                 return p + 2;
1722         }
1723         if (port_ptr)
1724                 *port_ptr = 0;
1725
1726         return p + 1;
1727 }