Separate the daemon options from the normal client options.
[rsync/rsync.git] / options.c
... / ...
CommitLineData
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
24extern int sanitize_paths;
25extern int select_timeout;
26extern struct exclude_list_struct exclude_list;
27extern struct exclude_list_struct server_exclude_list;
28
29int make_backups = 0;
30
31/**
32 * If 1, send the whole file as literal data rather than trying to
33 * create an incremental diff.
34 *
35 * If -1, then look at whether we're local or remote and go by that.
36 *
37 * @sa disable_deltas_p()
38 **/
39int whole_file = -1;
40
41int archive_mode = 0;
42int keep_dirlinks = 0;
43int copy_links = 0;
44int preserve_links = 0;
45int preserve_hard_links = 0;
46int preserve_perms = 0;
47int preserve_devices = 0;
48int preserve_uid = 0;
49int preserve_gid = 0;
50int preserve_times = 0;
51int update_only = 0;
52int cvs_exclude = 0;
53int dry_run = 0;
54int local_server = 0;
55int ignore_times = 0;
56int delete_mode = 0;
57int delete_excluded = 0;
58int one_file_system = 0;
59int protocol_version = PROTOCOL_VERSION;
60int sparse_files = 0;
61int do_compression = 0;
62int am_root = 0;
63int orig_umask = 0;
64int relative_paths = -1;
65int implied_dirs = 1;
66int numeric_ids = 0;
67int force_delete = 0;
68int io_timeout = 0;
69int read_only = 0;
70int module_id = -1;
71int am_server = 0;
72int am_sender = 0;
73int am_generator = 0;
74char *files_from = NULL;
75int filesfrom_fd = -1;
76char *remote_filesfrom_file = NULL;
77int eol_nulls = 0;
78int recurse = 0;
79int am_daemon = 0;
80int daemon_over_rsh = 0;
81int do_stats = 0;
82int do_progress = 0;
83int keep_partial = 0;
84int safe_symlinks = 0;
85int copy_unsafe_links = 0;
86int size_only = 0;
87int bwlimit = 0;
88size_t bwlimit_writemax = 0;
89int delete_after = 0;
90int only_existing = 0;
91int opt_ignore_existing = 0;
92int max_delete = 0;
93OFF_T max_size = 0;
94int ignore_errors = 0;
95int modify_window = 0;
96int blocking_io = -1;
97int checksum_seed = 0;
98int inplace = 0;
99unsigned int block_size = 0;
100
101
102/** Network address family. **/
103#ifdef INET6
104int default_af_hint = 0; /* Any protocol */
105#else
106int default_af_hint = AF_INET; /* Must use IPv4 */
107#endif
108
109/** Do not go into the background when run as --daemon. Good
110 * for debugging and required for running as a service on W32,
111 * or under Unix process-monitors. **/
112int no_detach = 0;
113
114int write_batch = 0;
115int read_batch = 0;
116int backup_dir_len = 0;
117int backup_suffix_len;
118unsigned int backup_dir_remainder;
119
120char *backup_suffix = NULL;
121char *tmpdir = NULL;
122char *partial_dir = NULL;
123char *compare_dest = NULL;
124char *config_file = NULL;
125char *shell_cmd = NULL;
126char *log_format = NULL;
127char *password_file = NULL;
128char *rsync_path = RSYNC_PATH;
129char *backup_dir = NULL;
130char backup_dir_buf[MAXPATHLEN];
131int rsync_port = RSYNC_PORT;
132int link_dest = 0;
133
134int verbose = 0;
135int quiet = 0;
136int always_checksum = 0;
137int list_only = 0;
138
139#define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
140char *batch_name = NULL;
141
142static int daemon_opt; /* sets am_daemon after option error-reporting */
143static int modify_window_set;
144static char *max_size_arg;
145
146/** Local address to bind. As a character string because it's
147 * interpreted by the IPv6 layer: should be a numeric IP4 or IP6
148 * address, or a hostname. **/
149char *bind_address;
150
151
152static void print_rsync_version(enum logcode f)
153{
154 char const *got_socketpair = "no ";
155 char const *have_inplace = "no ";
156 char const *hardlinks = "no ";
157 char const *links = "no ";
158 char const *ipv6 = "no ";
159 STRUCT_STAT *dumstat;
160
161#ifdef HAVE_SOCKETPAIR
162 got_socketpair = "";
163#endif
164
165#if HAVE_FTRUNCATE
166 have_inplace = "";
167#endif
168
169#if SUPPORT_HARD_LINKS
170 hardlinks = "";
171#endif
172
173#if SUPPORT_LINKS
174 links = "";
175#endif
176
177#if INET6
178 ipv6 = "";
179#endif
180
181 rprintf(f, "%s version %s protocol version %d\n",
182 RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION);
183 rprintf(f,
184 "Copyright (C) 1996-2004 by Andrew Tridgell and others\n");
185 rprintf(f, "<http://rsync.samba.org/>\n");
186 rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
187 "%shard links, %ssymlinks, batchfiles, \n",
188 (int) (sizeof (OFF_T) * 8),
189 got_socketpair, hardlinks, links);
190
191 /* Note that this field may not have type ino_t. It depends
192 * on the complicated interaction between largefile feature
193 * macros. */
194 rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
195 have_inplace, ipv6,
196 (int) (sizeof dumstat->st_ino * 8),
197 (int) (sizeof (uint64) * 8));
198#ifdef MAINTAINER_MODE
199 rprintf(f, " panic action: \"%s\"\n",
200 get_panic_action());
201#endif
202
203#ifdef INT64_IS_OFF_T
204 if (sizeof (int64) < 8)
205 rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
206#endif
207
208 rprintf(f,
209"\n"
210"rsync comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
211"are welcome to redistribute it under certain conditions. See the GNU\n"
212"General Public Licence for details.\n"
213 );
214}
215
216
217void usage(enum logcode F)
218{
219 print_rsync_version(F);
220
221 rprintf(F,"\nrsync is a file transfer program capable of efficient remote update\nvia a fast differencing algorithm.\n\n");
222
223 rprintf(F,"Usage: rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST\n");
224 rprintf(F," or rsync [OPTION]... [USER@]HOST:SRC DEST\n");
225 rprintf(F," or rsync [OPTION]... SRC [SRC]... DEST\n");
226 rprintf(F," or rsync [OPTION]... [USER@]HOST::SRC [DEST]\n");
227 rprintf(F," or rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST\n");
228 rprintf(F," or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]\n");
229 rprintf(F," or rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST\n");
230 rprintf(F,"SRC on single-colon remote HOST will be expanded by remote shell\n");
231 rprintf(F,"SRC on server remote HOST may contain shell wildcards or multiple\n");
232 rprintf(F," sources separated by space as long as they have same top-level\n");
233 rprintf(F,"\nOptions\n");
234 rprintf(F," -v, --verbose increase verbosity\n");
235 rprintf(F," -q, --quiet decrease verbosity\n");
236 rprintf(F," -c, --checksum always checksum\n");
237 rprintf(F," -a, --archive archive mode, equivalent to -rlptgoD (no -H)\n");
238 rprintf(F," -r, --recursive recurse into directories\n");
239 rprintf(F," -R, --relative use relative path names\n");
240 rprintf(F," --no-relative turn off --relative\n");
241 rprintf(F," --no-implied-dirs don't send implied dirs with -R\n");
242 rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n");
243 rprintf(F," --backup-dir make backups into this directory\n");
244 rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
245 rprintf(F," -u, --update update only (don't overwrite newer files)\n");
246 rprintf(F," --inplace update destination files inplace (SEE MAN PAGE)\n");
247 rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
248 rprintf(F," -l, --links copy symlinks as symlinks\n");
249 rprintf(F," -L, --copy-links copy the referent of all symlinks\n");
250 rprintf(F," --copy-unsafe-links copy the referent of \"unsafe\" symlinks\n");
251 rprintf(F," --safe-links ignore \"unsafe\" symlinks\n");
252 rprintf(F," -H, --hard-links preserve hard links\n");
253 rprintf(F," -p, --perms preserve permissions\n");
254 rprintf(F," -o, --owner preserve owner (root only)\n");
255 rprintf(F," -g, --group preserve group\n");
256 rprintf(F," -D, --devices preserve devices (root only)\n");
257 rprintf(F," -t, --times preserve times\n");
258 rprintf(F," -S, --sparse handle sparse files efficiently\n");
259 rprintf(F," -n, --dry-run show what would have been transferred\n");
260 rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
261 rprintf(F," --no-whole-file turn off --whole-file\n");
262 rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
263 rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n");
264 rprintf(F," -e, --rsh=COMMAND specify the remote shell\n");
265 rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
266 rprintf(F," --existing only update files that already exist\n");
267 rprintf(F," --ignore-existing ignore files that already exist on receiving side\n");
268 rprintf(F," --delete delete files that don't exist on the sending side\n");
269 rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
270 rprintf(F," --delete-after receiver deletes after transferring, not before\n");
271 rprintf(F," --ignore-errors delete even if there are I/O errors\n");
272 rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
273 rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n");
274 rprintf(F," --partial keep partially transferred files\n");
275 rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n");
276 rprintf(F," --force force deletion of directories even if not empty\n");
277 rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
278 rprintf(F," --timeout=TIME set I/O timeout in seconds\n");
279 rprintf(F," -I, --ignore-times turn off mod time & file size quick check\n");
280 rprintf(F," --size-only ignore mod time for quick check (use size)\n");
281 rprintf(F," --modify-window=NUM compare mod times with reduced accuracy\n");
282 rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n");
283 rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
284 rprintf(F," --link-dest=DIR create hardlinks to DIR for unchanged files\n");
285 rprintf(F," -P equivalent to --partial --progress\n");
286 rprintf(F," -z, --compress compress file data\n");
287 rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
288 rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n");
289 rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n");
290 rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n");
291 rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
292 rprintf(F," --files-from=FILE read FILE for list of source-file names\n");
293 rprintf(F," -0, --from0 all *-from file lists are delimited by nulls\n");
294 rprintf(F," --version print version number\n");
295 rprintf(F," --blocking-io use blocking I/O for the remote shell\n");
296 rprintf(F," --no-blocking-io turn off --blocking-io\n");
297 rprintf(F," --stats give some file transfer stats\n");
298 rprintf(F," --progress show progress during transfer\n");
299 rprintf(F," --log-format=FORMAT log file transfers using specified format\n");
300 rprintf(F," --password-file=FILE get password from FILE\n");
301 rprintf(F," --bwlimit=KBPS limit I/O bandwidth, KBytes per second\n");
302 rprintf(F," --write-batch=FILE write a batch to FILE\n");
303 rprintf(F," --read-batch=FILE read a batch from FILE\n");
304#ifdef INET6
305 rprintf(F," -4, --ipv4 prefer IPv4\n");
306 rprintf(F," -6, --ipv6 prefer IPv6\n");
307#endif
308 rprintf(F," -h, --help show this help screen\n");
309
310 rprintf(F,"\nUse \"rsync --daemon --help\" to see the daemon-mode command-line options.\n");
311 rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) man pages for full documentation.\n");
312 rprintf(F,"See http://rsync.samba.org/ for updates, bug reports, and answers\n");
313}
314
315enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
316 OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
317 OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
318 OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT, OPT_MAX_SIZE,
319 OPT_REFUSED_BASE = 9000};
320
321static struct poptOption long_options[] = {
322 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
323 {"version", 0, POPT_ARG_NONE, 0, OPT_VERSION, 0, 0},
324 {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 },
325 {"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 },
326 {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 },
327 {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 },
328 {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 },
329 {"modify-window", 0, POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 },
330 {"one-file-system", 'x', POPT_ARG_NONE, &one_file_system, 0, 0, 0 },
331 {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 },
332 {"existing", 0, POPT_ARG_NONE, &only_existing, 0, 0, 0 },
333 {"ignore-existing", 0, POPT_ARG_NONE, &opt_ignore_existing, 0, 0, 0 },
334 {"delete-after", 0, POPT_ARG_NONE, 0, OPT_DELETE_AFTER, 0, 0 },
335 {"delete-excluded", 0, POPT_ARG_NONE, 0, OPT_DELETE_EXCLUDED, 0, 0 },
336 {"force", 0, POPT_ARG_NONE, &force_delete, 0, 0, 0 },
337 {"numeric-ids", 0, POPT_ARG_NONE, &numeric_ids, 0, 0, 0 },
338 {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 },
339 {"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 },
340 {"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 },
341 {"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 },
342 {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 },
343 {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
344 {"backup", 'b', POPT_ARG_NONE, &make_backups, 0, 0, 0 },
345 {"dry-run", 'n', POPT_ARG_NONE, &dry_run, 0, 0, 0 },
346 {"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
347 {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 },
348 {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
349 {"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
350 {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
351 {"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 },
352 {"copy-links", 'L', POPT_ARG_NONE, &copy_links, 0, 0, 0 },
353 {"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 },
354 {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 },
355 {"copy-unsafe-links", 0, POPT_ARG_NONE, &copy_unsafe_links, 0, 0, 0 },
356 {"perms", 'p', POPT_ARG_NONE, &preserve_perms, 0, 0, 0 },
357 {"owner", 'o', POPT_ARG_NONE, &preserve_uid, 0, 0, 0 },
358 {"group", 'g', POPT_ARG_NONE, &preserve_gid, 0, 0, 0 },
359 {"devices", 'D', POPT_ARG_NONE, &preserve_devices, 0, 0, 0 },
360 {"times", 't', POPT_ARG_NONE, &preserve_times, 0, 0, 0 },
361 {"checksum", 'c', POPT_ARG_NONE, &always_checksum, 0, 0, 0 },
362 {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 },
363 {"quiet", 'q', POPT_ARG_NONE, 0, 'q', 0, 0 },
364 {"archive", 'a', POPT_ARG_NONE, &archive_mode, 0, 0, 0 },
365 {"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 },
366 {"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 },
367 {"recursive", 'r', POPT_ARG_NONE, &recurse, 0, 0, 0 },
368 {"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 },
369 {"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 },
370 {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
371 {"block-size", 'B', POPT_ARG_INT, &block_size, 0, 0, 0 },
372 {"max-delete", 0, POPT_ARG_INT, &max_delete, 0, 0, 0 },
373 {"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 },
374 {"timeout", 0, POPT_ARG_INT, &io_timeout, OPT_TIMEOUT, 0, 0 },
375 {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
376 {"compare-dest", 0, POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
377 {"link-dest", 0, POPT_ARG_STRING, &compare_dest, OPT_LINK_DEST, 0, 0 },
378 /* TODO: Should this take an optional int giving the compression level? */
379 {"compress", 'z', POPT_ARG_NONE, &do_compression, 0, 0, 0 },
380 {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 },
381 {"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 },
382 {"partial", 0, POPT_ARG_NONE, &keep_partial, 0, 0, 0 },
383 {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 },
384 {"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 },
385 {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 },
386 {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 },
387 {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 },
388 {"log-format", 0, POPT_ARG_STRING, &log_format, 0, 0, 0 },
389 {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 },
390 {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
391 {"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links, 0, 0, 0 },
392 {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 },
393 {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 },
394 {"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 },
395 {"from0", '0', POPT_ARG_NONE, &eol_nulls, 0, 0, 0},
396 {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 },
397 {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
398 {"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
399#ifdef INET6
400 {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
401 {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
402#endif
403 /* All these options switch us into daemon-mode option-parsing. */
404 {"address", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
405 {"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 },
406 {"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
407 {"no-detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 },
408 {"port", 0, POPT_ARG_INT, 0, OPT_DAEMON, 0, 0 },
409 {0,0,0,0, 0, 0, 0}
410};
411
412static void daemon_usage(enum logcode F)
413{
414 print_rsync_version(F);
415
416 rprintf(F,"\nUsage: rsync --daemon [OPTION]...\n");
417 rprintf(F," --address=ADDRESS bind to the specified address\n");
418 rprintf(F," --config=FILE specify alternate rsyncd.conf file\n");
419 rprintf(F," --no-detach do not detach from the parent\n");
420 rprintf(F," --port=PORT specify alternate rsyncd port number\n");
421#ifdef INET6
422 rprintf(F," -4, --ipv4 prefer IPv4\n");
423 rprintf(F," -6, --ipv6 prefer IPv6\n");
424#endif
425 rprintf(F," -h, --help show this help screen\n");
426
427 rprintf(F,"\nIf you were not trying to invoke rsync as a daemon, avoid using any of the\n");
428 rprintf(F,"daemon-specific rsync options. See also the rsyncd.conf(5) man page.\n");
429}
430
431static struct poptOption long_daemon_options[] = {
432 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
433 {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 },
434 {"config", 0, POPT_ARG_STRING, &config_file, 0, 0, 0 },
435 {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 },
436#ifdef INET6
437 {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 },
438 {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 },
439#endif
440 {"no-detach", 0, POPT_ARG_NONE, &no_detach, 0, 0, 0 },
441 {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 },
442 {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
443 {"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 },
444 {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
445 {0,0,0,0, 0, 0, 0}
446};
447
448
449static char err_buf[200];
450
451
452/**
453 * Store the option error message, if any, so that we can log the
454 * connection attempt (which requires parsing the options), and then
455 * show the error later on.
456 **/
457void option_error(void)
458{
459 if (!err_buf[0]) {
460 strcpy(err_buf, "Error parsing options: "
461 "option may be supported on client but not on server?\n");
462 }
463
464 rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
465}
466
467
468/**
469 * Tweak the option table to disable all options that the rsyncd.conf
470 * file has told us to refuse.
471 **/
472static void set_refuse_options(char *bp)
473{
474 struct poptOption *op;
475 char *cp, shortname[2];
476 int is_wild, found_match;
477
478 shortname[1] = '\0';
479
480 while (1) {
481 while (*bp == ' ') bp++;
482 if (!*bp)
483 break;
484 if ((cp = strchr(bp, ' ')) != NULL)
485 *cp= '\0';
486 /* If they specify "delete", reject all delete options. */
487 if (strcmp(bp, "delete") == 0)
488 bp = "delete*";
489 is_wild = strpbrk(bp, "*?[") != NULL;
490 found_match = 0;
491 for (op = long_options; ; op++) {
492 *shortname = op->shortName;
493 if (!op->longName && !*shortname)
494 break;
495 if ((op->longName && wildmatch(bp, op->longName))
496 || (*shortname && wildmatch(bp, shortname))) {
497 op->val = (op - long_options) + OPT_REFUSED_BASE;
498 found_match = 1;
499 if (!is_wild)
500 break;
501 }
502 }
503 if (!found_match) {
504 rprintf(FLOG, "No match for refuse-options string \"%s\"\n",
505 bp);
506 }
507 if (!cp)
508 break;
509 *cp = ' ';
510 bp = cp + 1;
511 }
512}
513
514
515static int count_args(const char **argv)
516{
517 int i = 0;
518
519 if (argv) {
520 while (argv[i] != NULL)
521 i++;
522 }
523
524 return i;
525}
526
527
528/**
529 * Process command line arguments. Called on both local and remote.
530 *
531 * @retval 1 if all options are OK; with globals set to appropriate
532 * values
533 *
534 * @retval 0 on error, with err_buf containing an explanation
535 **/
536int parse_arguments(int *argc, const char ***argv, int frommain)
537{
538 int opt;
539 char *ref = lp_refuse_options(module_id);
540 const char *arg;
541 poptContext pc;
542
543 if (ref && *ref)
544 set_refuse_options(ref);
545
546 /* TODO: Call poptReadDefaultConfig; handle errors. */
547
548 /* The context leaks in case of an error, but if there's a
549 * problem we always exit anyhow. */
550 pc = poptGetContext(RSYNC_NAME, *argc, *argv, long_options, 0);
551
552 while ((opt = poptGetNextOpt(pc)) != -1) {
553 /* most options are handled automatically by popt;
554 * only special cases are returned and listed here. */
555
556 switch (opt) {
557 case OPT_VERSION:
558 print_rsync_version(FINFO);
559 exit_cleanup(0);
560
561 case OPT_DAEMON:
562 if (am_daemon) {
563 strcpy(err_buf, "Attempt to hack rsync thwarted!\n");
564 return 0;
565 }
566 poptFreeContext(pc);
567 pc = poptGetContext(RSYNC_NAME, *argc, *argv,
568 long_daemon_options, 0);
569 while ((opt = poptGetNextOpt(pc)) != -1) {
570 switch (opt) {
571 case 'h':
572 daemon_usage(FINFO);
573 exit_cleanup(0);
574
575 default:
576 rprintf(FERROR,
577 "rsync: %s: %s (in daemon mode)\n",
578 poptBadOption(pc, POPT_BADOPTION_NOALIAS),
579 poptStrerror(opt));
580 goto daemon_error;
581 }
582 }
583 if (!daemon_opt) {
584 rprintf(FERROR, "Daemon option(s) used without --daemon.\n");
585 daemon_error:
586 rprintf(FERROR,
587 "(Type \"rsync --daemon --help\" for assistance with daemon mode.)\n");
588 exit_cleanup(RERR_SYNTAX);
589 }
590 *argv = poptGetArgs(pc);
591 *argc = count_args(*argv);
592 daemon_opt = 0;
593 am_daemon = 1;
594 return 1;
595
596 case OPT_MODIFY_WINDOW:
597 /* The value has already been set by popt, but
598 * we need to remember that we're using a
599 * non-default setting. */
600 modify_window_set = 1;
601 break;
602
603 case OPT_DELETE_AFTER:
604 delete_after = 1;
605 delete_mode = 1;
606 break;
607
608 case OPT_DELETE_EXCLUDED:
609 delete_excluded = 1;
610 delete_mode = 1;
611 break;
612
613 case OPT_EXCLUDE:
614 add_exclude(&exclude_list, poptGetOptArg(pc), 0);
615 break;
616
617 case OPT_INCLUDE:
618 add_exclude(&exclude_list, poptGetOptArg(pc),
619 XFLG_DEF_INCLUDE);
620 break;
621
622 case OPT_EXCLUDE_FROM:
623 case OPT_INCLUDE_FROM:
624 arg = poptGetOptArg(pc);
625 if (sanitize_paths)
626 arg = sanitize_path(NULL, arg, NULL, 0);
627 if (server_exclude_list.head) {
628 char *cp = (char *)arg;
629 clean_fname(cp, 1);
630 if (check_exclude(&server_exclude_list, cp, 0) < 0)
631 goto options_rejected;
632 }
633 add_exclude_file(&exclude_list, arg, XFLG_FATAL_ERRORS
634 | (opt == OPT_INCLUDE_FROM
635 ? XFLG_DEF_INCLUDE : 0));
636 break;
637
638 case 'h':
639 usage(FINFO);
640 exit_cleanup(0);
641
642 case 'v':
643 verbose++;
644 break;
645
646 case 'q':
647 if (frommain)
648 quiet++;
649 break;
650
651 case OPT_SENDER:
652 if (!am_server) {
653 usage(FERROR);
654 exit_cleanup(RERR_SYNTAX);
655 }
656 am_sender = 1;
657 break;
658
659 case 'P':
660 do_progress = 1;
661 keep_partial = 1;
662 break;
663
664 case OPT_WRITE_BATCH:
665 /* batch_name is already set */
666 write_batch = 1;
667 break;
668
669 case OPT_READ_BATCH:
670 /* batch_name is already set */
671 read_batch = 1;
672 break;
673
674 case OPT_MAX_SIZE:
675 for (arg = max_size_arg; isdigit(*arg); arg++) {}
676 if (*arg == '.')
677 for (arg++; isdigit(*arg); arg++) {}
678 switch (*arg) {
679 case 'k': case 'K':
680 max_size = atof(max_size_arg) * 1024;
681 break;
682 case 'm': case 'M':
683 max_size = atof(max_size_arg) * 1024*1024;
684 break;
685 case 'g': case 'G':
686 max_size = atof(max_size_arg) * 1024*1024*1024;
687 break;
688 case '\0':
689 max_size = atof(max_size_arg);
690 break;
691 default:
692 max_size = 0;
693 break;
694 }
695 if (max_size <= 0) {
696 rprintf(FERROR,
697 "--max-size value is invalid: %s\n",
698 max_size_arg);
699 exit_cleanup(RERR_SYNTAX);
700 }
701 break;
702
703 case OPT_TIMEOUT:
704 if (io_timeout && io_timeout < select_timeout)
705 select_timeout = io_timeout;
706 break;
707
708 case OPT_LINK_DEST:
709#if HAVE_LINK
710 link_dest = 1;
711 break;
712#else
713 snprintf(err_buf, sizeof err_buf,
714 "hard links are not supported on this %s\n",
715 am_server ? "server" : "client");
716 return 0;
717#endif
718
719 default:
720 /* A large opt value means that set_refuse_options()
721 * turned this option off (opt-BASE is its index). */
722 if (opt >= OPT_REFUSED_BASE) {
723 struct poptOption *op =
724 &long_options[opt-OPT_REFUSED_BASE];
725 int n = snprintf(err_buf, sizeof err_buf,
726 "The server is configured to refuse --%s\n",
727 op->longName) - 1;
728 if (op->shortName) {
729 snprintf(err_buf+n, sizeof err_buf-n,
730 " (-%c)\n", op->shortName);
731 }
732 } else {
733 snprintf(err_buf, sizeof err_buf, "%s%s: %s\n",
734 am_server ? "on remote machine: " : "",
735 poptBadOption(pc, POPT_BADOPTION_NOALIAS),
736 poptStrerror(opt));
737 }
738 return 0;
739 }
740 }
741
742#if !SUPPORT_LINKS
743 if (preserve_links && !am_sender) {
744 snprintf(err_buf, sizeof err_buf,
745 "symlinks are not supported on this %s\n",
746 am_server ? "server" : "client");
747 return 0;
748 }
749#endif
750
751#if !SUPPORT_HARD_LINKS
752 if (preserve_hard_links) {
753 snprintf(err_buf, sizeof err_buf,
754 "hard links are not supported on this %s\n",
755 am_server ? "server" : "client");
756 return 0;
757 }
758#endif
759
760 if (write_batch && read_batch) {
761 snprintf(err_buf, sizeof err_buf,
762 "--write-batch and --read-batch can not be used together\n");
763 return 0;
764 }
765 if (write_batch || read_batch) {
766 if (dry_run) {
767 snprintf(err_buf, sizeof err_buf,
768 "--%s-batch cannot be used with --dry_run (-n)\n",
769 write_batch ? "write" : "read");
770 return 0;
771 }
772 if (am_server) {
773 rprintf(FINFO,
774 "ignoring --%s-batch option sent to server\n",
775 write_batch ? "write" : "read");
776 /* We don't actually exit_cleanup(), so that we can
777 * still service older version clients that still send
778 * batch args to server. */
779 read_batch = write_batch = 0;
780 batch_name = NULL;
781 }
782 }
783 if (read_batch && files_from) {
784 snprintf(err_buf, sizeof err_buf,
785 "--read-batch cannot be used with --files-from\n");
786 return 0;
787 }
788 if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
789 snprintf(err_buf, sizeof err_buf,
790 "the batch-file name must be %d characters or less.\n",
791 MAX_BATCH_NAME_LEN);
792 return 0;
793 }
794
795 if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
796 snprintf(err_buf, sizeof err_buf,
797 "the --temp-dir path is WAY too long.\n");
798 return 0;
799 }
800
801 if (archive_mode) {
802 if (!files_from)
803 recurse = 1;
804#if SUPPORT_LINKS
805 preserve_links = 1;
806#endif
807 preserve_perms = 1;
808 preserve_times = 1;
809 preserve_gid = 1;
810 preserve_uid = 1;
811 preserve_devices = 1;
812 }
813
814 if (relative_paths < 0)
815 relative_paths = files_from? 1 : 0;
816
817 *argv = poptGetArgs(pc);
818 *argc = count_args(*argv);
819
820 if (sanitize_paths) {
821 int i;
822 for (i = *argc; i-- > 0; )
823 (*argv)[i] = sanitize_path(NULL, (*argv)[i], "", 0);
824 if (tmpdir)
825 tmpdir = sanitize_path(NULL, tmpdir, NULL, 0);
826 if (partial_dir)
827 partial_dir = sanitize_path(NULL, partial_dir, NULL, 0);
828 if (compare_dest)
829 compare_dest = sanitize_path(NULL, compare_dest, NULL, 0);
830 if (backup_dir)
831 backup_dir = sanitize_path(NULL, backup_dir, NULL, 0);
832 if (files_from)
833 files_from = sanitize_path(NULL, files_from, NULL, 0);
834 }
835 if (server_exclude_list.head && !am_sender) {
836 struct exclude_list_struct *elp = &server_exclude_list;
837 if (tmpdir) {
838 clean_fname(tmpdir, 1);
839 if (check_exclude(elp, tmpdir, 1) < 0)
840 goto options_rejected;
841 }
842 if (partial_dir) {
843 clean_fname(partial_dir, 1);
844 if (check_exclude(elp, partial_dir, 1) < 0)
845 goto options_rejected;
846 }
847 if (compare_dest) {
848 clean_fname(compare_dest, 1);
849 if (check_exclude(elp, compare_dest, 1) < 0)
850 goto options_rejected;
851 }
852 if (backup_dir) {
853 clean_fname(backup_dir, 1);
854 if (check_exclude(elp, backup_dir, 1) < 0)
855 goto options_rejected;
856 }
857 }
858 if (server_exclude_list.head && files_from) {
859 clean_fname(files_from, 1);
860 if (check_exclude(&server_exclude_list, files_from, 0) < 0) {
861 options_rejected:
862 snprintf(err_buf, sizeof err_buf,
863 "Your options have been rejected by the server.\n");
864 return 0;
865 }
866 }
867
868 if (!backup_suffix)
869 backup_suffix = backup_dir ? "" : BACKUP_SUFFIX;
870 backup_suffix_len = strlen(backup_suffix);
871 if (strchr(backup_suffix, '/') != NULL) {
872 snprintf(err_buf, sizeof err_buf,
873 "--suffix cannot contain slashes: %s\n",
874 backup_suffix);
875 return 0;
876 }
877 if (backup_dir) {
878 backup_dir_len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf);
879 backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len;
880 if (backup_dir_remainder < 32) {
881 snprintf(err_buf, sizeof err_buf,
882 "the --backup-dir path is WAY too long.\n");
883 return 0;
884 }
885 if (backup_dir_buf[backup_dir_len - 1] != '/') {
886 backup_dir_buf[backup_dir_len++] = '/';
887 backup_dir_buf[backup_dir_len] = '\0';
888 }
889 if (verbose > 1 && !am_sender)
890 rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf);
891 } else if (!backup_suffix_len && (!am_server || !am_sender)) {
892 snprintf(err_buf, sizeof err_buf,
893 "--suffix cannot be a null string without --backup-dir\n");
894 return 0;
895 }
896
897 if (do_progress && !verbose)
898 verbose = 1;
899
900 if (bwlimit) {
901 bwlimit_writemax = (size_t)bwlimit * 128;
902 if (bwlimit_writemax < 512)
903 bwlimit_writemax = 512;
904 }
905
906 if (inplace) {
907#if HAVE_FTRUNCATE
908 if (partial_dir) {
909 snprintf(err_buf, sizeof err_buf,
910 "--inplace cannot be used with --partial-dir\n");
911 return 0;
912 }
913 keep_partial = 0;
914#else
915 snprintf(err_buf, sizeof err_buf,
916 "--inplace is not supported on this %s\n",
917 am_server ? "server" : "client");
918 return 0;
919#endif
920 if (compare_dest) {
921 snprintf(err_buf, sizeof err_buf,
922 "--inplace does not yet work with %s\n",
923 link_dest ? "--link-dest" : "--compare-dest");
924 return 0;
925 }
926 } else {
927 if (keep_partial && !partial_dir)
928 partial_dir = getenv("RSYNC_PARTIAL_DIR");
929 if (partial_dir) {
930 if (!*partial_dir || strcmp(partial_dir, ".") == 0)
931 partial_dir = NULL;
932 else if (*partial_dir != '/') {
933 add_exclude(&exclude_list, partial_dir,
934 XFLG_DIRECTORY);
935 }
936 keep_partial = 1;
937 }
938 }
939
940 if (files_from) {
941 char *colon;
942 if (*argc > 2 || (!am_daemon && *argc == 1)) {
943 usage(FERROR);
944 exit_cleanup(RERR_SYNTAX);
945 }
946 if (strcmp(files_from, "-") == 0) {
947 filesfrom_fd = 0;
948 if (am_server)
949 remote_filesfrom_file = "-";
950 }
951 else if ((colon = find_colon(files_from)) != 0) {
952 if (am_server) {
953 usage(FERROR);
954 exit_cleanup(RERR_SYNTAX);
955 }
956 remote_filesfrom_file = colon+1 + (colon[1] == ':');
957 if (strcmp(remote_filesfrom_file, "-") == 0) {
958 snprintf(err_buf, sizeof err_buf,
959 "Invalid --files-from remote filename\n");
960 return 0;
961 }
962 } else {
963 filesfrom_fd = open(files_from, O_RDONLY|O_BINARY);
964 if (filesfrom_fd < 0) {
965 snprintf(err_buf, sizeof err_buf,
966 "failed to open files-from file %s: %s\n",
967 files_from, strerror(errno));
968 return 0;
969 }
970 }
971 }
972
973 return 1;
974}
975
976
977/**
978 * Construct a filtered list of options to pass through from the
979 * client to the server.
980 *
981 * This involves setting options that will tell the server how to
982 * behave, and also filtering out options that are processed only
983 * locally.
984 **/
985void server_options(char **args,int *argc)
986{
987 int ac = *argc;
988 static char argstr[50];
989 char *arg;
990
991 int i, x;
992
993 if (blocking_io == -1)
994 blocking_io = 0;
995
996 args[ac++] = "--server";
997
998 if (daemon_over_rsh) {
999 args[ac++] = "--daemon";
1000 *argc = ac;
1001 /* if we're passing --daemon, we're done */
1002 return;
1003 }
1004
1005 if (!am_sender)
1006 args[ac++] = "--sender";
1007
1008 x = 1;
1009 argstr[0] = '-';
1010 for (i = 0; i < verbose; i++)
1011 argstr[x++] = 'v';
1012
1013 /* the -q option is intentionally left out */
1014 if (make_backups)
1015 argstr[x++] = 'b';
1016 if (update_only)
1017 argstr[x++] = 'u';
1018 if (dry_run)
1019 argstr[x++] = 'n';
1020 if (preserve_links)
1021 argstr[x++] = 'l';
1022 if (copy_links)
1023 argstr[x++] = 'L';
1024 if (keep_dirlinks && am_sender)
1025 argstr[x++] = 'K';
1026
1027 if (whole_file > 0)
1028 argstr[x++] = 'W';
1029 /* We don't need to send --no-whole-file, because it's the
1030 * default for remote transfers, and in any case old versions
1031 * of rsync will not understand it. */
1032
1033 if (preserve_hard_links)
1034 argstr[x++] = 'H';
1035 if (preserve_uid)
1036 argstr[x++] = 'o';
1037 if (preserve_gid)
1038 argstr[x++] = 'g';
1039 if (preserve_devices)
1040 argstr[x++] = 'D';
1041 if (preserve_times)
1042 argstr[x++] = 't';
1043 if (preserve_perms)
1044 argstr[x++] = 'p';
1045 if (recurse)
1046 argstr[x++] = 'r';
1047 if (always_checksum)
1048 argstr[x++] = 'c';
1049 if (cvs_exclude)
1050 argstr[x++] = 'C';
1051 if (ignore_times)
1052 argstr[x++] = 'I';
1053 if (relative_paths)
1054 argstr[x++] = 'R';
1055 if (one_file_system)
1056 argstr[x++] = 'x';
1057 if (sparse_files)
1058 argstr[x++] = 'S';
1059 if (do_compression)
1060 argstr[x++] = 'z';
1061
1062 /* this is a complete hack - blame Rusty
1063
1064 this is a hack to make the list_only (remote file list)
1065 more useful */
1066 if (list_only && !recurse)
1067 argstr[x++] = 'r';
1068
1069 argstr[x] = 0;
1070
1071 if (x != 1)
1072 args[ac++] = argstr;
1073
1074 if (block_size) {
1075 if (asprintf(&arg, "-B%u", block_size) < 0)
1076 goto oom;
1077 args[ac++] = arg;
1078 }
1079
1080 if (max_delete && am_sender) {
1081 if (asprintf(&arg, "--max-delete=%d", max_delete) < 0)
1082 goto oom;
1083 args[ac++] = arg;
1084 }
1085
1086 if (max_size && am_sender) {
1087 args[ac++] = "--max-size";
1088 args[ac++] = max_size_arg;
1089 }
1090
1091 if (io_timeout) {
1092 if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
1093 goto oom;
1094 args[ac++] = arg;
1095 }
1096
1097 if (bwlimit) {
1098 if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0)
1099 goto oom;
1100 args[ac++] = arg;
1101 }
1102
1103 if (backup_dir) {
1104 args[ac++] = "--backup-dir";
1105 args[ac++] = backup_dir;
1106 }
1107
1108 /* Only send --suffix if it specifies a non-default value. */
1109 if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) {
1110 /* We use the following syntax to avoid weirdness with '~'. */
1111 if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0)
1112 goto oom;
1113 args[ac++] = arg;
1114 }
1115
1116 if (am_sender) {
1117 if (delete_excluded)
1118 args[ac++] = "--delete-excluded";
1119 else if (delete_mode)
1120 args[ac++] = "--delete";
1121
1122 if (delete_after)
1123 args[ac++] = "--delete-after";
1124
1125 if (force_delete)
1126 args[ac++] = "--force";
1127 }
1128
1129 if (size_only)
1130 args[ac++] = "--size-only";
1131
1132 if (modify_window_set) {
1133 if (asprintf(&arg, "--modify-window=%d", modify_window) < 0)
1134 goto oom;
1135 args[ac++] = arg;
1136 }
1137
1138 if (checksum_seed) {
1139 if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0)
1140 goto oom;
1141 args[ac++] = arg;
1142 }
1143
1144 if (partial_dir && am_sender) {
1145 args[ac++] = "--partial-dir";
1146 args[ac++] = partial_dir;
1147 } else if (keep_partial)
1148 args[ac++] = "--partial";
1149
1150 if (ignore_errors)
1151 args[ac++] = "--ignore-errors";
1152
1153 if (copy_unsafe_links)
1154 args[ac++] = "--copy-unsafe-links";
1155
1156 if (safe_symlinks)
1157 args[ac++] = "--safe-links";
1158
1159 if (numeric_ids)
1160 args[ac++] = "--numeric-ids";
1161
1162 if (only_existing && am_sender)
1163 args[ac++] = "--existing";
1164
1165 if (opt_ignore_existing && am_sender)
1166 args[ac++] = "--ignore-existing";
1167
1168 if (inplace)
1169 args[ac++] = "--inplace";
1170
1171 if (tmpdir) {
1172 args[ac++] = "--temp-dir";
1173 args[ac++] = tmpdir;
1174 }
1175
1176 if (compare_dest && am_sender) {
1177 /* the server only needs this option if it is not the sender,
1178 * and it may be an older version that doesn't know this
1179 * option, so don't send it if client is the sender.
1180 */
1181 args[ac++] = link_dest ? "--link-dest" : "--compare-dest";
1182 args[ac++] = compare_dest;
1183 }
1184
1185 if (files_from && (!am_sender || remote_filesfrom_file)) {
1186 if (remote_filesfrom_file) {
1187 args[ac++] = "--files-from";
1188 args[ac++] = remote_filesfrom_file;
1189 if (eol_nulls)
1190 args[ac++] = "--from0";
1191 } else {
1192 args[ac++] = "--files-from=-";
1193 args[ac++] = "--from0";
1194 }
1195 }
1196
1197 *argc = ac;
1198 return;
1199
1200 oom:
1201 out_of_memory("server_options");
1202}
1203
1204/**
1205 * Return the position of a ':' IF it is not part of a filename (i.e. as
1206 * long as it doesn't occur after a slash.
1207 */
1208char *find_colon(char *s)
1209{
1210 char *p, *p2;
1211
1212 p = strchr(s,':');
1213 if (!p)
1214 return NULL;
1215
1216 /* now check to see if there is a / in the string before the : - if there is then
1217 discard the colon on the assumption that the : is part of a filename */
1218 p2 = strchr(s,'/');
1219 if (p2 && p2 < p)
1220 return NULL;
1221
1222 return p;
1223}