Changed the parsing of suffixes for --min-size and --max-size a little.
[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," -m, --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," -h, --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,
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",            'h', POPT_ARG_NONE,   0, 'h', 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",  'm', 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," -h, --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 'h':
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 #ifndef SUPPORT_LINKS
1016         if (preserve_links && !am_sender) {
1017                 snprintf(err_buf, sizeof err_buf,
1018                          "symlinks are not supported on this %s\n",
1019                          am_server ? "server" : "client");
1020                 return 0;
1021         }
1022 #endif
1023
1024 #ifndef SUPPORT_HARD_LINKS
1025         if (preserve_hard_links) {
1026                 snprintf(err_buf, sizeof err_buf,
1027                          "hard links are not supported on this %s\n",
1028                          am_server ? "server" : "client");
1029                 return 0;
1030         }
1031 #endif
1032
1033         if (write_batch && read_batch) {
1034                 snprintf(err_buf, sizeof err_buf,
1035                         "--write-batch and --read-batch can not be used together\n");
1036                 return 0;
1037         }
1038         if (write_batch > 0 || read_batch) {
1039                 if (am_server) {
1040                         rprintf(FINFO,
1041                                 "ignoring --%s-batch option sent to server\n",
1042                                 write_batch ? "write" : "read");
1043                         /* We don't actually exit_cleanup(), so that we can
1044                          * still service older version clients that still send
1045                          * batch args to server. */
1046                         read_batch = write_batch = 0;
1047                         batch_name = NULL;
1048                 } else if (dry_run)
1049                         write_batch = 0;
1050         }
1051         if (read_batch && files_from) {
1052                 snprintf(err_buf, sizeof err_buf,
1053                         "--read-batch cannot be used with --files-from\n");
1054                 return 0;
1055         }
1056         if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
1057                 snprintf(err_buf, sizeof err_buf,
1058                         "the batch-file name must be %d characters or less.\n",
1059                         MAX_BATCH_NAME_LEN);
1060                 return 0;
1061         }
1062
1063         if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
1064                 snprintf(err_buf, sizeof err_buf,
1065                          "the --temp-dir path is WAY too long.\n");
1066                 return 0;
1067         }
1068
1069         if (compare_dest + copy_dest + link_dest > 1) {
1070                 snprintf(err_buf, sizeof err_buf,
1071                         "You may not mix --compare-dest, --copy-dest, and --link-dest.\n");
1072                 return 0;
1073         }
1074
1075         if (files_from) {
1076                 if (recurse == 1) /* preserve recurse == 2 */
1077                         recurse = 0;
1078                 if (xfer_dirs < 0)
1079                         xfer_dirs = 1;
1080         }
1081
1082         if (xfer_dirs < 1)
1083                 xfer_dirs = recurse || list_only;
1084
1085         if (relative_paths < 0)
1086                 relative_paths = files_from? 1 : 0;
1087         if (!relative_paths)
1088                 implied_dirs = 0;
1089
1090         if (!!delete_before + delete_during + delete_after > 1) {
1091                 snprintf(err_buf, sizeof err_buf,
1092                         "You may not combine multiple --delete-WHEN options.\n");
1093                 return 0;
1094         }
1095         if (!xfer_dirs) {
1096                 delete_before = delete_during = delete_after = 0;
1097                 delete_mode = delete_excluded = 0;
1098         } else if (delete_before || delete_during || delete_after)
1099                 delete_mode = 1;
1100         else if (delete_mode || delete_excluded) {
1101                 if (refused_delete_before) {
1102                         create_refuse_error(refused_delete_before);
1103                         return 0;
1104                 }
1105                 delete_mode = delete_before = 1;
1106         }
1107
1108         if (delete_mode && refused_delete) {
1109                 create_refuse_error(refused_delete);
1110                 return 0;
1111         }
1112
1113         if (remove_sent_files) {
1114                 /* We only want to infer this refusal of --remove-sent-files
1115                  * via the refusal of "delete", not any of the "delete-FOO"
1116                  * options. */
1117                 if (refused_delete && am_sender) {
1118                         create_refuse_error(refused_delete);
1119                         return 0;
1120                 }
1121                 need_messages_from_generator = 1;
1122         }
1123
1124         *argv = poptGetArgs(pc);
1125         *argc = count_args(*argv);
1126
1127         if (sanitize_paths) {
1128                 int i;
1129                 for (i = *argc; i-- > 0; )
1130                         (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0);
1131                 if (tmpdir)
1132                         tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
1133                 if (partial_dir)
1134                         partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
1135                 if (backup_dir)
1136                         backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
1137         }
1138         if (server_filter_list.head && !am_sender) {
1139                 struct filter_list_struct *elp = &server_filter_list;
1140                 int i;
1141                 if (tmpdir) {
1142                         if (!*tmpdir)
1143                                 goto options_rejected;
1144                         clean_fname(tmpdir, 1);
1145                         if (check_filter(elp, tmpdir, 1) < 0)
1146                                 goto options_rejected;
1147                 }
1148                 if (partial_dir && *partial_dir) {
1149                         clean_fname(partial_dir, 1);
1150                         if (check_filter(elp, partial_dir, 1) < 0)
1151                                 goto options_rejected;
1152                 }
1153                 for (i = 0; i < basis_dir_cnt; i++) {
1154                         if (!*basis_dir[i])
1155                                 goto options_rejected;
1156                         clean_fname(basis_dir[i], 1);
1157                         if (check_filter(elp, basis_dir[i], 1) < 0)
1158                                 goto options_rejected;
1159                 }
1160                 if (backup_dir) {
1161                         if (!*backup_dir)
1162                                 goto options_rejected;
1163                         clean_fname(backup_dir, 1);
1164                         if (check_filter(elp, backup_dir, 1) < 0) {
1165                             options_rejected:
1166                                 snprintf(err_buf, sizeof err_buf,
1167                                     "Your options have been rejected by the server.\n");
1168                                 return 0;
1169                         }
1170                 }
1171         }
1172
1173         if (!backup_suffix)
1174                 backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
1175         backup_suffix_len = strlen(backup_suffix);
1176         if (strchr(backup_suffix, '/') != NULL) {
1177                 snprintf(err_buf, sizeof err_buf,
1178                         "--suffix cannot contain slashes: %s\n",
1179                         backup_suffix);
1180                 return 0;
1181         }
1182         if (backup_dir) {
1183                 backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
1184                 backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
1185                 if (backup_dir_remainder < 32) {
1186                         snprintf(err_buf, sizeof err_buf,
1187                                 "the --backup-dir path is WAY too long.\n");
1188                         return 0;
1189                 }
1190                 if (backup_dir_buf[backup_dir_len - 1] != '/') {
1191                         backup_dir_buf[backup_dir_len++] = '/';
1192                         backup_dir_buf[backup_dir_len] = '\0';
1193                 }
1194                 if (verbose > 1 && !am_sender) {
1195                         rprintf(FINFO, "backup_dir is %s\n",
1196                                 safe_fname(backup_dir_buf));
1197                 }
1198         } else if (!backup_suffix_len && (!am_server || !am_sender)) {
1199                 snprintf(err_buf, sizeof err_buf,
1200                         "--suffix cannot be a null string without --backup-dir\n");
1201                 return 0;
1202         }
1203         if (make_backups && !backup_dir)
1204                 omit_dir_times = 1;
1205
1206         if (chmod_mode && !(chmod_modes = parse_chmod(chmod_mode))) {
1207                 snprintf(err_buf, sizeof err_buf,
1208                     "Invalid argument passed to chmod\n");
1209                 return 0;
1210         }
1211
1212         if (log_format) {
1213                 if (log_format_has(log_format, 'i'))
1214                         log_format_has_i = 1;
1215                 if (!log_format_has(log_format, 'b')
1216                  && !log_format_has(log_format, 'c'))
1217                         log_before_transfer = !am_server;
1218         } else if (itemize_changes) {
1219                 log_format = "%i %n%L";
1220                 log_format_has_i = 1;
1221                 log_before_transfer = !am_server;
1222         }
1223
1224         if ((do_progress || dry_run) && !verbose && !log_before_transfer
1225             && !am_server)
1226                 verbose = 1;
1227
1228         if (dry_run)
1229                 do_xfers = 0;
1230
1231         set_io_timeout(io_timeout);
1232
1233         if (verbose && !log_format) {
1234                 log_format = "%n%L";
1235                 log_before_transfer = !am_server;
1236         }
1237         if (log_format_has_i || log_format_has(log_format, 'o'))
1238                 log_format_has_o_or_i = 1;
1239
1240         if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit))
1241                 bwlimit = daemon_bwlimit;
1242         if (bwlimit) {
1243                 bwlimit_writemax = (size_t)bwlimit * 128;
1244                 if (bwlimit_writemax < 512)
1245                         bwlimit_writemax = 512;
1246         }
1247
1248         if (sparse_files && inplace) {
1249                 /* Note: we don't check for this below, because --append is
1250                  * OK with --sparse (as long as redos are handled right). */
1251                 snprintf(err_buf, sizeof err_buf,
1252                          "--sparse cannot be used with --inplace\n");
1253                 return 0;
1254         }
1255
1256         if (append_mode) {
1257                 if (whole_file > 0) {
1258                         snprintf(err_buf, sizeof err_buf,
1259                                  "--append cannot be used with --whole-file\n");
1260                         return 0;
1261                 }
1262                 if (refused_inplace) {
1263                         create_refuse_error(refused_inplace);
1264                         return 0;
1265                 }
1266                 inplace = 1;
1267         }
1268
1269         if (delay_updates && !partial_dir)
1270                 partial_dir = partialdir_for_delayupdate;
1271
1272         if (inplace) {
1273 #ifdef HAVE_FTRUNCATE
1274                 if (partial_dir) {
1275                         snprintf(err_buf, sizeof err_buf,
1276                                  "--%s cannot be used with --%s\n",
1277                                  append_mode ? "append" : "inplace",
1278                                  delay_updates ? "delay-updates" : "partial-dir");
1279                         return 0;
1280                 }
1281                 /* --inplace implies --partial for refusal purposes, but we
1282                  * clear the keep_partial flag for internal logic purposes. */
1283                 if (refused_partial) {
1284                         create_refuse_error(refused_partial);
1285                         return 0;
1286                 }
1287                 keep_partial = 0;
1288 #else
1289                 snprintf(err_buf, sizeof err_buf,
1290                          "--%s is not supported on this %s\n",
1291                          append_mode ? "append" : "inplace",
1292                          am_server ? "server" : "client");
1293                 return 0;
1294 #endif
1295         } else {
1296                 if (keep_partial && !partial_dir) {
1297                         if ((arg = getenv("RSYNC_PARTIAL_DIR")) != NULL && *arg)
1298                                 partial_dir = strdup(arg);
1299                 }
1300                 if (partial_dir) {
1301                         if (*partial_dir)
1302                                 clean_fname(partial_dir, 1);
1303                         if (!*partial_dir || strcmp(partial_dir, ".") == 0)
1304                                 partial_dir = NULL;
1305                         else if (*partial_dir != '/') {
1306                                 parse_rule(&filter_list, partial_dir,
1307                                     MATCHFLG_NO_PREFIXES|MATCHFLG_DIRECTORY, 0);
1308                         }
1309                         if (!partial_dir && refused_partial) {
1310                                 create_refuse_error(refused_partial);
1311                                 return 0;
1312                         }
1313                         keep_partial = 1;
1314                 }
1315         }
1316
1317         if (files_from) {
1318                 char *h, *p;
1319                 int q;
1320                 if (*argc > 2 || (!am_daemon && *argc == 1)) {
1321                         usage(FERROR);
1322                         exit_cleanup(RERR_SYNTAX);
1323                 }
1324                 if (strcmp(files_from, "-") == 0) {
1325                         filesfrom_fd = 0;
1326                         if (am_server)
1327                                 filesfrom_host = ""; /* reading from socket */
1328                 } else if ((p = check_for_hostspec(files_from, &h, &q)) != 0) {
1329                         if (am_server) {
1330                                 snprintf(err_buf, sizeof err_buf,
1331                                         "The --files-from sent to the server cannot specify a host.\n");
1332                                 return 0;
1333                         }
1334                         files_from = p;
1335                         filesfrom_host = h;
1336                         if (strcmp(files_from, "-") == 0) {
1337                                 snprintf(err_buf, sizeof err_buf,
1338                                         "Invalid --files-from remote filename\n");
1339                                 return 0;
1340                         }
1341                 } else {
1342                         if (sanitize_paths)
1343                                 files_from = sanitize_path(NULL, files_from, NULL, 0);
1344                         if (server_filter_list.head) {
1345                                 if (!*files_from)
1346                                         goto options_rejected;
1347                                 clean_fname(files_from, 1);
1348                                 if (check_filter(&server_filter_list, files_from, 0) < 0)
1349                                         goto options_rejected;
1350                         }
1351                         filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
1352                         if (filesfrom_fd < 0) {
1353                                 snprintf(err_buf, sizeof err_buf,
1354                                         "failed to open files-from file %s: %s\n",
1355                                         files_from, strerror(errno));
1356                                 return 0;
1357                         }
1358                 }
1359         }
1360
1361         am_starting_up = 0;
1362
1363         return 1;
1364 }
1365
1366
1367 /**
1368  * Construct a filtered list of options to pass through from the
1369  * client to the server.
1370  *
1371  * This involves setting options that will tell the server how to
1372  * behave, and also filtering out options that are processed only
1373  * locally.
1374  **/
1375 void server_options(char **args,int *argc)
1376 {
1377         static char argstr[64];
1378         int ac = *argc;
1379         char *arg;
1380
1381         int i, x;
1382
1383         if (blocking_io == -1)
1384                 blocking_io = 0;
1385
1386         args[ac++] = "--server";
1387
1388         if (daemon_over_rsh) {
1389                 args[ac++] = "--daemon";
1390                 *argc = ac;
1391                 /* if we're passing --daemon, we're done */
1392                 return;
1393         }
1394
1395         if (!am_sender)
1396                 args[ac++] = "--sender";
1397
1398         x = 1;
1399         argstr[0] = '-';
1400         for (i = 0; i < verbose; i++)
1401                 argstr[x++] = 'v';
1402
1403         /* the -q option is intentionally left out */
1404         if (make_backups)
1405                 argstr[x++] = 'b';
1406         if (update_only)
1407                 argstr[x++] = 'u';
1408         if (!do_xfers) /* NOT "dry_run"! */
1409                 argstr[x++] = 'n';
1410         if (preserve_links)
1411                 argstr[x++] = 'l';
1412         if (copy_links)
1413                 argstr[x++] = 'L';
1414         if (xfer_dirs > 1)
1415                 argstr[x++] = 'd';
1416         if (keep_dirlinks && am_sender)
1417                 argstr[x++] = 'K';
1418
1419         if (whole_file > 0)
1420                 argstr[x++] = 'W';
1421         /* We don't need to send --no-whole-file, because it's the
1422          * default for remote transfers, and in any case old versions
1423          * of rsync will not understand it. */
1424
1425         if (preserve_hard_links)
1426                 argstr[x++] = 'H';
1427         if (preserve_uid)
1428                 argstr[x++] = 'o';
1429         if (preserve_gid)
1430                 argstr[x++] = 'g';
1431         if (preserve_devices)
1432                 argstr[x++] = 'D';
1433         if (preserve_times)
1434                 argstr[x++] = 't';
1435         if (omit_dir_times == 2 && am_sender)
1436                 argstr[x++] = 'O';
1437         if (preserve_perms)
1438                 argstr[x++] = 'p';
1439         if (recurse)
1440                 argstr[x++] = 'r';
1441         if (always_checksum)
1442                 argstr[x++] = 'c';
1443         if (cvs_exclude)
1444                 argstr[x++] = 'C';
1445         if (ignore_times)
1446                 argstr[x++] = 'I';
1447         if (relative_paths)
1448                 argstr[x++] = 'R';
1449         if (one_file_system)
1450                 argstr[x++] = 'x';
1451         if (sparse_files)
1452                 argstr[x++] = 'S';
1453         if (do_compression)
1454                 argstr[x++] = 'z';
1455
1456         /* This is a complete hack - blame Rusty.  FIXME!
1457          * This hack is only needed for older rsync versions that
1458          * don't understand the --list-only option. */
1459         if (list_only == 1 && !recurse)
1460                 argstr[x++] = 'r';
1461
1462         argstr[x] = 0;
1463
1464         if (x != 1)
1465                 args[ac++] = argstr;
1466
1467         if (list_only > 1)
1468                 args[ac++] = "--list-only";
1469
1470         if (do_compression && def_compress_level != Z_DEFAULT_COMPRESSION) {
1471                 if (asprintf(&arg, "--compress-level=%d", def_compress_level) < 0)
1472                         goto oom;
1473                 args[ac++] = arg;
1474         }
1475
1476         /* The server side doesn't use our log-format, but in certain
1477          * circumstances they need to know a little about the option. */
1478         if (log_format && am_sender) {
1479                 if (log_format_has_i)
1480                         args[ac++] = "--log-format=%i";
1481                 else if (log_format_has_o_or_i)
1482                         args[ac++] = "--log-format=%o";
1483                 else if (!verbose)
1484                         args[ac++] = "--log-format=X";
1485         }
1486
1487         if (block_size) {
1488                 if (asprintf(&arg, "-B%lu", block_size) < 0)
1489                         goto oom;
1490                 args[ac++] = arg;
1491         }
1492
1493         if (max_delete && am_sender) {
1494                 if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
1495                         goto oom;
1496                 args[ac++] = arg;
1497         }
1498
1499         if (min_size && am_sender) {
1500                 args[ac++] = "--min-size";
1501                 args[ac++] = min_size_arg;
1502         }
1503
1504         if (max_size && am_sender) {
1505                 args[ac++] = "--max-size";
1506                 args[ac++] = max_size_arg;
1507         }
1508
1509         if (io_timeout) {
1510                 if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
1511                         goto oom;
1512                 args[ac++] = arg;
1513         }
1514
1515         if (bwlimit) {
1516                 if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0)
1517                         goto oom;
1518                 args[ac++] = arg;
1519         }
1520
1521         if (backup_dir) {
1522                 args[ac++] = "--backup-dir";
1523                 args[ac++] = backup_dir;
1524         }
1525
1526         /* Only send --suffix if it specifies a non-default value. */
1527         if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
1528                 /* We use the following syntax to avoid weirdness with '~'. */
1529                 if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
1530                         goto oom;
1531                 args[ac++] = arg;
1532         }
1533
1534         if (am_sender) {
1535                 if (delete_excluded)
1536                         args[ac++] = "--delete-excluded";
1537                 else if (delete_before == 1 || delete_after)
1538                         args[ac++] = "--delete";
1539                 if (delete_before > 1)
1540                         args[ac++] = "--delete-before";
1541                 if (delete_during)
1542                         args[ac++] = "--delete-during";
1543                 if (delete_after)
1544                         args[ac++] = "--delete-after";
1545                 if (force_delete)
1546                         args[ac++] = "--force";
1547                 if (write_batch < 0)
1548                         args[ac++] = "--only-write-batch=X";
1549         }
1550
1551         if (size_only)
1552                 args[ac++] = "--size-only";
1553
1554         if (modify_window_set) {
1555                 if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
1556                         goto oom;
1557                 args[ac++] = arg;
1558         }
1559
1560         if (checksum_seed) {
1561                 if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
1562                         goto oom;
1563                 args[ac++] = arg;
1564         }
1565
1566         if (partial_dir && am_sender) {
1567                 if (partial_dir != partialdir_for_delayupdate) {
1568                         args[ac++] = "--partial-dir";
1569                         args[ac++] = partial_dir;
1570                 }
1571                 if (delay_updates)
1572                         args[ac++] = "--delay-updates";
1573         } else if (keep_partial)
1574                 args[ac++] = "--partial";
1575
1576         if (ignore_errors)
1577                 args[ac++] = "--ignore-errors";
1578
1579         if (copy_unsafe_links)
1580                 args[ac++] = "--copy-unsafe-links";
1581
1582         if (safe_symlinks)
1583                 args[ac++] = "--safe-links";
1584
1585         if (numeric_ids)
1586                 args[ac++] = "--numeric-ids";
1587
1588         if (ignore_existing && am_sender)
1589                 args[ac++] = "--ignore-existing";
1590
1591         /* Backward compatibility: send --existing, not --ignore-non-existing. */
1592         if (ignore_non_existing && am_sender)
1593                 args[ac++] = "--existing";
1594
1595         if (append_mode)
1596                 args[ac++] = "--append";
1597         else if (inplace)
1598                 args[ac++] = "--inplace";
1599
1600         if (tmpdir) {
1601                 args[ac++] = "--temp-dir";
1602                 args[ac++] = tmpdir;
1603         }
1604
1605         if (basis_dir[0] && am_sender) {
1606                 /* the server only needs this option if it is not the sender,
1607                  *   and it may be an older version that doesn't know this
1608                  *   option, so don't send it if client is the sender.
1609                  */
1610                 int i;
1611                 for (i = 0; i < basis_dir_cnt; i++) {
1612                         args[ac++] = dest_option;
1613                         args[ac++] = basis_dir[i];
1614                 }
1615         }
1616
1617         if (chmod_mode && !am_sender) {
1618                 args[ac++] = "--chmod";
1619                 args[ac++] = chmod_mode;
1620         }
1621
1622         if (files_from && (!am_sender || filesfrom_host)) {
1623                 if (filesfrom_host) {
1624                         args[ac++] = "--files-from";
1625                         args[ac++] = files_from;
1626                         if (eol_nulls)
1627                                 args[ac++] = "--from0";
1628                 } else {
1629                         args[ac++] = "--files-from=-";
1630                         args[ac++] = "--from0";
1631                 }
1632                 if (!relative_paths)
1633                         args[ac++] = "--no-relative";
1634         }
1635         if (relative_paths && !implied_dirs && !am_sender)
1636                 args[ac++] = "--no-implied-dirs";
1637
1638         if (fuzzy_basis && am_sender)
1639                 args[ac++] = "--fuzzy";
1640
1641         if (remove_sent_files)
1642                 args[ac++] = "--remove-sent-files";
1643
1644         *argc = ac;
1645         return;
1646
1647     oom:
1648         out_of_memory("server_options");
1649 }
1650
1651 /* Look for a HOST specfication of the form "HOST:PATH", "HOST::PATH", or
1652  * "rsync://HOST:PORT/PATH".  If found, *host_ptr will be set to some allocated
1653  * memory with the HOST.  If a daemon-accessing spec was specified, the value
1654  * of *port_ptr will contain a non-0 port number, otherwise it will be set to
1655  * 0.  The return value is a pointer to the PATH.  Note that the HOST spec can
1656  * be an IPv6 literal address enclosed in '[' and ']' (such as "[::1]" or
1657  * "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */
1658 char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr)
1659 {
1660         char *p;
1661         int not_host;
1662
1663         if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) {
1664                 char *path;
1665                 int hostlen;
1666                 s += strlen(URL_PREFIX);
1667                 if ((p = strchr(s, '/')) != NULL) {
1668                         hostlen = p - s;
1669                         path = p + 1;
1670                 } else {
1671                         hostlen = strlen(s);
1672                         path = "";
1673                 }
1674                 if (*s == '[' && (p = strchr(s, ']')) != NULL) {
1675                         s++;
1676                         hostlen = p - s;
1677                         if (p[1] == ':')
1678                                 *port_ptr = atoi(p+2);
1679                 } else {
1680                         if ((p = strchr(s, ':')) != NULL) {
1681                                 hostlen = p - s;
1682                                 *port_ptr = atoi(p+1);
1683                         }
1684                 }
1685                 if (!*port_ptr)
1686                         *port_ptr = RSYNC_PORT;
1687                 *host_ptr = new_array(char, hostlen + 1);
1688                 strlcpy(*host_ptr, s, hostlen + 1);
1689                 return path;
1690         }
1691
1692         if (*s == '[' && (p = strchr(s, ']')) != NULL && p[1] == ':') {
1693                 s++;
1694                 *p = '\0';
1695                 not_host = strchr(s, '/') || !strchr(s, ':');
1696                 *p = ']';
1697                 if (not_host)
1698                         return NULL;
1699                 p++;
1700         } else {
1701                 if (!(p = strchr(s, ':')))
1702                         return NULL;
1703                 *p = '\0';
1704                 not_host = strchr(s, '/') != NULL;
1705                 *p = ':';
1706                 if (not_host)
1707                         return NULL;
1708         }
1709
1710         *host_ptr = new_array(char, p - s + 1);
1711         strlcpy(*host_ptr, s, p - s + 1);
1712
1713         if (p[1] == ':') {
1714                 if (port_ptr && !*port_ptr)
1715                         *port_ptr = RSYNC_PORT;
1716                 return p + 2;
1717         }
1718         if (port_ptr)
1719                 *port_ptr = 0;
1720
1721         return p + 1;
1722 }