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