2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/types.h>
31 #include <sys/socket.h>
48 #define USAGE_OPTFMT " %-12s %s\n"
49 #define USAGE_OPTFMTSUB " %-14s %s\n", ""
57 lprintf(-1, "Usage: %s [options] supfile\n", basename(argv0));
58 lprintf(-1, " Options:\n");
59 lprintf(-1, USAGE_OPTFMT, "-1", "Don't retry automatically on failure "
60 "(same as \"-r 0\")");
61 lprintf(-1, USAGE_OPTFMT, "-4", "Force usage of IPv4 addresses");
62 lprintf(-1, USAGE_OPTFMT, "-6", "Force usage of IPv6 addresses");
63 lprintf(-1, USAGE_OPTFMT, "-A addr",
64 "Bind local socket to a specific address");
65 lprintf(-1, USAGE_OPTFMT, "-b base",
66 "Override supfile's \"base\" directory");
67 lprintf(-1, USAGE_OPTFMT, "-c collDir",
68 "Subdirectory of \"base\" for collections (default \"sup\")");
69 lprintf(-1, USAGE_OPTFMT, "-d delLimit",
70 "Allow at most \"delLimit\" file deletions (default unlimited)");
71 lprintf(-1, USAGE_OPTFMT, "-h host",
72 "Override supfile's \"host\" name");
73 lprintf(-1, USAGE_OPTFMT, "-i pattern",
74 "Include only files/directories matching pattern.");
75 lprintf(-1, USAGE_OPTFMTSUB,
76 "May be repeated for an OR operation. Default is");
77 lprintf(-1, USAGE_OPTFMTSUB, "to include each entire collection.");
78 lprintf(-1, USAGE_OPTFMT, "-k",
79 "Keep bad temporary files when fixups are required");
80 lprintf(-1, USAGE_OPTFMT, "-l lockfile",
81 "Lock file during update; fail if already locked");
82 lprintf(-1, USAGE_OPTFMT, "-L n",
83 "Verbosity level (0..2, default 1)");
84 lprintf(-1, USAGE_OPTFMT, "-p port",
85 "Alternate server port (default 5999)");
86 lprintf(-1, USAGE_OPTFMT, "-r n",
87 "Maximum retries on transient errors (default unlimited)");
88 lprintf(-1, USAGE_OPTFMT, "-s",
89 "Don't stat client files; trust the checkouts file");
90 lprintf(-1, USAGE_OPTFMT, "-v", "Print version and exit");
91 lprintf(-1, USAGE_OPTFMT, "-z", "Enable compression for all "
93 lprintf(-1, USAGE_OPTFMT, "-Z", "Disable compression for all "
98 main(int argc, char *argv[])
101 struct backoff_timer *timer;
102 struct config *config;
103 struct coll *override;
104 struct addrinfo *res;
105 struct sockaddr *laddr;
108 char *argv0, *file, *lockfile;
109 int family, error, lockfd, lflag, overridemask;
110 int c, i, deletelim, port, retries, status;
125 override = coll_new(NULL);
128 while ((c = getopt(argc, argv,
129 "146A:b:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) {
141 error = getaddrinfo(optarg, NULL, NULL, &res);
143 lprintf(-1, "%s: %s\n", optarg,
144 gai_strerror(error));
147 laddrlen = res->ai_addrlen;
148 laddr = xmalloc(laddrlen);
149 memcpy(laddr, res->ai_addr, laddrlen);
153 if (override->co_base != NULL)
154 free(override->co_base);
155 override->co_base = xstrdup(optarg);
158 override->co_colldir = optarg;
161 error = asciitoint(optarg, &deletelim, 0);
162 if (error || deletelim < 0) {
163 lprintf(-1, "Invalid deletion limit\n");
169 /* For compatibility. */
172 if (override->co_host != NULL)
173 free(override->co_host);
174 override->co_host = xstrdup(optarg);
177 pattlist_add(override->co_accepts, optarg);
180 override->co_options |= CO_KEEPBADFILES;
181 overridemask |= CO_KEEPBADFILES;
186 lockfd = open(lockfile,
187 O_CREAT | O_WRONLY | O_TRUNC, 0700);
189 error = flock(lockfd, LOCK_EX | LOCK_NB);
190 if (error == -1 && errno == EWOULDBLOCK) {
193 lprintf(-1, "\"%s\" is already locked "
194 "by another process\n", lockfile);
198 if (lockfd == -1 || error == -1) {
201 lprintf(-1, "Error locking \"%s\": %s\n",
202 lockfile, strerror(errno));
205 lock = stream_open_fd(lockfd,
206 NULL, stream_write_fd, NULL);
207 (void)stream_printf(lock, "%10ld\n", (long)getpid());
211 error = asciitoint(optarg, &verbose, 0);
213 lprintf(-1, "Invalid verbosity\n");
219 /* Use specified server port. */
220 error = asciitoint(optarg, &port, 0);
222 lprintf(-1, "Invalid server port\n");
226 if (port <= 0 || port >= 65536) {
227 lprintf(-1, "Invalid port %d\n", port);
231 lprintf(-1, "Reserved port %d not permitted\n",
237 /* For compatibility. */
238 if (strcmp(optarg, "m") != 0) {
240 "Client only supports multiplexed mode\n");
245 error = asciitoint(optarg, &retries, 0);
246 if (error || retries < 0) {
247 lprintf(-1, "Invalid retry limit\n");
253 override->co_options |= CO_TRUSTSTATUSFILE;
254 overridemask |= CO_TRUSTSTATUSFILE;
257 lprintf(0, "CVSup client written in C\n");
258 lprintf(0, "Software version: %s\n", PROTO_SWVER);
259 lprintf(0, "Protocol version: %d.%d\n",
260 PROTO_MAJ, PROTO_MIN);
261 lprintf(0, "http://mu.org/~mux/csup.html\n");
265 /* Force compression on all collections. */
266 override->co_options |= CO_COMPRESS;
267 overridemask |= CO_COMPRESS;
270 /* Disables compression on all collections. */
271 override->co_options &= ~CO_COMPRESS;
272 overridemask &= ~CO_COMPRESS;
290 lprintf(2, "Parsing supfile \"%s\"\n", file);
291 config = config_init(file, override, overridemask);
296 if (config_checkcolls(config) == 0) {
297 lprintf(-1, "No collections selected\n");
302 config->laddr = laddr;
303 config->laddrlen = laddrlen;
305 config->deletelim = deletelim;
306 lprintf(2, "Connecting to %s\n", config->host);
309 fattr_init(); /* Initialize the fattr API. */
310 timer = bt_new(300, 7200, 2.0, 0.1);
312 status = proto_connect(config, family, port);
313 if (status == STATUS_SUCCESS) {
314 status = proto_run(config);
315 if (status != STATUS_TRANSIENTFAILURE)
318 if (retries >= 0 && i >= retries)
320 nexttry = time(0) + bt_get(timer);
321 localtime_r(&nexttry, &tm);
322 lprintf(1, "Will retry at %02d:%02d:%02d\n",
323 tm.tm_hour, tm.tm_min, tm.tm_sec);
325 lprintf(1, "Retrying\n");
332 flock(lockfd, LOCK_UN);
336 if (status != STATUS_SUCCESS)