main.c revision 156230
1156230Smux/*- 2156230Smux * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org> 3156230Smux * All rights reserved. 4156230Smux * 5156230Smux * Redistribution and use in source and binary forms, with or without 6156230Smux * modification, are permitted provided that the following conditions 7156230Smux * are met: 8156230Smux * 1. Redistributions of source code must retain the above copyright 9156230Smux * notice, this list of conditions and the following disclaimer. 10156230Smux * 2. Redistributions in binary form must reproduce the above copyright 11156230Smux * notice, this list of conditions and the following disclaimer in the 12156230Smux * documentation and/or other materials provided with the distribution. 13156230Smux * 14156230Smux * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17156230Smux * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24156230Smux * SUCH DAMAGE. 25156230Smux * 26156230Smux * $FreeBSD: vendor/csup/dist/contrib/csup/main.c 156230 2006-03-03 04:11:29Z mux $ 27156230Smux */ 28156230Smux 29156230Smux#include <sys/file.h> 30156230Smux#include <sys/types.h> 31156230Smux#include <sys/socket.h> 32156230Smux 33156230Smux#include <errno.h> 34156230Smux#include <fcntl.h> 35156230Smux#include <libgen.h> 36156230Smux#include <netdb.h> 37156230Smux#include <stdio.h> 38156230Smux#include <stdlib.h> 39156230Smux#include <string.h> 40156230Smux#include <unistd.h> 41156230Smux 42156230Smux#include "config.h" 43156230Smux#include "fattr.h" 44156230Smux#include "misc.h" 45156230Smux#include "proto.h" 46156230Smux#include "stream.h" 47156230Smux 48156230Smux#define USAGE_OPTFMT " %-12s %s\n" 49156230Smux#define USAGE_OPTFMTSUB " %-14s %s\n", "" 50156230Smux 51156230Smuxint verbose = 1; 52156230Smux 53156230Smuxstatic void 54156230Smuxusage(char *argv0) 55156230Smux{ 56156230Smux 57156230Smux lprintf(-1, "Usage: %s [options] supfile\n", basename(argv0)); 58156230Smux lprintf(-1, " Options:\n"); 59156230Smux lprintf(-1, USAGE_OPTFMT, "-1", "Don't retry automatically on failure " 60156230Smux "(same as \"-r 0\")"); 61156230Smux lprintf(-1, USAGE_OPTFMT, "-4", "Force usage of IPv4 addresses"); 62156230Smux lprintf(-1, USAGE_OPTFMT, "-6", "Force usage of IPv6 addresses"); 63156230Smux lprintf(-1, USAGE_OPTFMT, "-A addr", 64156230Smux "Bind local socket to a specific address"); 65156230Smux lprintf(-1, USAGE_OPTFMT, "-b base", 66156230Smux "Override supfile's \"base\" directory"); 67156230Smux lprintf(-1, USAGE_OPTFMT, "-c collDir", 68156230Smux "Subdirectory of \"base\" for collections (default \"sup\")"); 69156230Smux lprintf(-1, USAGE_OPTFMT, "-h host", 70156230Smux "Override supfile's \"host\" name"); 71156230Smux lprintf(-1, USAGE_OPTFMT, "-i pattern", 72156230Smux "Include only files/directories matching pattern."); 73156230Smux lprintf(-1, USAGE_OPTFMTSUB, 74156230Smux "May be repeated for an OR operation. Default is"); 75156230Smux lprintf(-1, USAGE_OPTFMTSUB, "to include each entire collection."); 76156230Smux lprintf(-1, USAGE_OPTFMT, "-l lockfile", 77156230Smux "Lock file during update; fail if already locked"); 78156230Smux lprintf(-1, USAGE_OPTFMT, "-L n", 79156230Smux "Verbosity level (0..2, default 1)"); 80156230Smux lprintf(-1, USAGE_OPTFMT, "-p port", 81156230Smux "Alternate server port (default 5999)"); 82156230Smux lprintf(-1, USAGE_OPTFMT, "-r n", 83156230Smux "Maximum retries on transient errors (default unlimited)"); 84156230Smux lprintf(-1, USAGE_OPTFMT, "-s", 85156230Smux "Don't stat client files; trust the checkouts file"); 86156230Smux lprintf(-1, USAGE_OPTFMT, "-v", "Print version and exit"); 87156230Smux lprintf(-1, USAGE_OPTFMT, "-z", "Enable compression for all " 88156230Smux "collections"); 89156230Smux lprintf(-1, USAGE_OPTFMT, "-Z", "Disable compression for all " 90156230Smux "collections"); 91156230Smux} 92156230Smux 93156230Smuxint 94156230Smuxmain(int argc, char *argv[]) 95156230Smux{ 96156230Smux struct tm tm; 97156230Smux struct backoff_timer *timer; 98156230Smux struct config *config; 99156230Smux struct coll *override; 100156230Smux struct addrinfo *res; 101156230Smux struct sockaddr *laddr; 102156230Smux socklen_t laddrlen; 103156230Smux struct stream *lock; 104156230Smux char *argv0, *file, *lockfile; 105156230Smux uint16_t port; 106156230Smux int family, error, lockfd, lflag, overridemask; 107156230Smux int c, i, retries, status; 108156230Smux time_t nexttry; 109156230Smux 110156230Smux error = 0; 111156230Smux family = PF_UNSPEC; 112156230Smux port = 0; 113156230Smux lflag = 0; 114156230Smux lockfd = 0; 115156230Smux nexttry = 0; 116156230Smux retries = -1; 117156230Smux argv0 = argv[0]; 118156230Smux laddr = NULL; 119156230Smux laddrlen = 0; 120156230Smux lockfile = NULL; 121156230Smux override = coll_new(NULL); 122156230Smux overridemask = 0; 123156230Smux 124156230Smux while ((c = getopt(argc, argv, "146A:b:c:gh:i:l:L:p:P:r:svzZ")) != -1) { 125156230Smux switch (c) { 126156230Smux case '1': 127156230Smux retries = 0; 128156230Smux break; 129156230Smux case '4': 130156230Smux family = AF_INET; 131156230Smux break; 132156230Smux case '6': 133156230Smux family = AF_INET6; 134156230Smux break; 135156230Smux case 'A': 136156230Smux error = getaddrinfo(optarg, NULL, NULL, &res); 137156230Smux if (error) { 138156230Smux lprintf(-1, "%s: %s\n", optarg, 139156230Smux gai_strerror(error)); 140156230Smux return (1); 141156230Smux } 142156230Smux laddrlen = res->ai_addrlen; 143156230Smux laddr = xmalloc(laddrlen); 144156230Smux memcpy(laddr, res->ai_addr, laddrlen); 145156230Smux freeaddrinfo(res); 146156230Smux break; 147156230Smux case 'b': 148156230Smux if (override->co_base != NULL) 149156230Smux free(override->co_base); 150156230Smux override->co_base = xstrdup(optarg); 151156230Smux break; 152156230Smux case 'c': 153156230Smux override->co_colldir = optarg; 154156230Smux break; 155156230Smux case 'g': 156156230Smux /* For compatibility. */ 157156230Smux break; 158156230Smux case 'h': 159156230Smux if (override->co_host != NULL) 160156230Smux free(override->co_host); 161156230Smux override->co_host = xstrdup(optarg); 162156230Smux break; 163156230Smux case 'i': 164156230Smux pattlist_add(override->co_accepts, optarg); 165156230Smux break; 166156230Smux case 'l': 167156230Smux lockfile = optarg; 168156230Smux lflag = 1; 169156230Smux lockfd = open(lockfile, 170156230Smux O_CREAT | O_WRONLY | O_TRUNC, 0700); 171156230Smux if (lockfd != -1) { 172156230Smux error = flock(lockfd, LOCK_EX | LOCK_NB); 173156230Smux if (error == -1 && errno == EWOULDBLOCK) { 174156230Smux if (lockfd != -1) 175156230Smux close(lockfd); 176156230Smux lprintf(-1, "\"%s\" is already locked " 177156230Smux "by another process\n", lockfile); 178156230Smux return (1); 179156230Smux } 180156230Smux } 181156230Smux if (lockfd == -1 || error == -1) { 182156230Smux if (lockfd != -1) 183156230Smux close(lockfd); 184156230Smux lprintf(-1, "Error locking \"%s\": %s\n", 185156230Smux lockfile, strerror(errno)); 186156230Smux return (1); 187156230Smux } 188156230Smux lock = stream_open_fd(lockfd, 189156230Smux NULL, stream_write_fd, NULL); 190156230Smux (void)stream_printf(lock, "%10ld\n", (long)getpid()); 191156230Smux stream_close(lock); 192156230Smux break; 193156230Smux case 'L': 194156230Smux errno = 0; 195156230Smux verbose = strtol(optarg, NULL, 0); 196156230Smux if (errno == EINVAL) { 197156230Smux lprintf(-1, "Invalid verbosity\n"); 198156230Smux usage(argv0); 199156230Smux return (1); 200156230Smux } 201156230Smux break; 202156230Smux case 'p': 203156230Smux /* Use specified server port. */ 204156230Smux errno = 0; 205156230Smux port = strtol(optarg, NULL, 0); 206156230Smux if (errno == EINVAL) { 207156230Smux lprintf(-1, "Invalid server port\n"); 208156230Smux usage(argv0); 209156230Smux return (1); 210156230Smux } 211156230Smux break; 212156230Smux case 'P': 213156230Smux /* For compatibility. */ 214156230Smux if (strcmp(optarg, "m") != 0) { 215156230Smux lprintf(-1, 216156230Smux "Client only supports multiplexed mode\n"); 217156230Smux return (1); 218156230Smux } 219156230Smux break; 220156230Smux case 'r': 221156230Smux errno = 0; 222156230Smux retries = strtol(optarg, NULL, 0); 223156230Smux if (errno == EINVAL || retries < 0) { 224156230Smux lprintf(-1, "Invalid retry limit\n"); 225156230Smux usage(argv0); 226156230Smux return (1); 227156230Smux } 228156230Smux break; 229156230Smux case 's': 230156230Smux override->co_options |= CO_TRUSTSTATUSFILE; 231156230Smux overridemask |= CO_TRUSTSTATUSFILE; 232156230Smux break; 233156230Smux case 'v': 234156230Smux lprintf(0, "CVSup client written in C\n"); 235156230Smux lprintf(0, "Software version: %s\n", PROTO_SWVER); 236156230Smux lprintf(0, "Protocol version: %d.%d\n", 237156230Smux PROTO_MAJ, PROTO_MIN); 238156230Smux lprintf(0, "http://mu.org/~mux/csup.html\n"); 239156230Smux return (0); 240156230Smux break; 241156230Smux case 'z': 242156230Smux /* Force compression on all collections. */ 243156230Smux override->co_options |= CO_COMPRESS; 244156230Smux overridemask |= CO_COMPRESS; 245156230Smux break; 246156230Smux case 'Z': 247156230Smux /* Disables compression on all collections. */ 248156230Smux override->co_options &= ~CO_COMPRESS; 249156230Smux overridemask &= ~CO_COMPRESS; 250156230Smux break; 251156230Smux case '?': 252156230Smux default: 253156230Smux usage(argv0); 254156230Smux return (1); 255156230Smux } 256156230Smux } 257156230Smux 258156230Smux argc -= optind; 259156230Smux argv += optind; 260156230Smux 261156230Smux if (argc < 1) { 262156230Smux usage(argv0); 263156230Smux return (1); 264156230Smux } 265156230Smux 266156230Smux file = argv[0]; 267156230Smux lprintf(2, "Parsing supfile \"%s\"\n", file); 268156230Smux config = config_init(file, override, overridemask); 269156230Smux coll_free(override); 270156230Smux if (config == NULL) 271156230Smux return (1); 272156230Smux 273156230Smux if (laddr != NULL) { 274156230Smux config->laddr = laddr; 275156230Smux config->laddrlen = laddrlen; 276156230Smux } 277156230Smux if (config_checkcolls(config) == 0) { 278156230Smux lprintf(-1, "No collections selected\n"); 279156230Smux return (1); 280156230Smux } 281156230Smux 282156230Smux lprintf(2, "Connecting to %s\n", config->host); 283156230Smux 284156230Smux i = 0; 285156230Smux fattr_init(); /* Initialize the fattr API. */ 286156230Smux timer = bt_new(300, 7200, 2.0, 0.1); 287156230Smux for (;;) { 288156230Smux status = proto_connect(config, family, port); 289156230Smux if (status == STATUS_SUCCESS) { 290156230Smux status = proto_run(config); 291156230Smux if (status != STATUS_TRANSIENTFAILURE) 292156230Smux break; 293156230Smux } 294156230Smux if (retries >= 0 && i >= retries) 295156230Smux break; 296156230Smux nexttry = time(0) + bt_get(timer); 297156230Smux localtime_r(&nexttry, &tm); 298156230Smux lprintf(1, "Will retry at %02d:%02d:%02d\n", 299156230Smux tm.tm_hour, tm.tm_min, tm.tm_sec); 300156230Smux bt_pause(timer); 301156230Smux lprintf(1, "Retrying\n"); 302156230Smux i++; 303156230Smux } 304156230Smux bt_free(timer); 305156230Smux fattr_fini(); 306156230Smux if (lflag) { 307156230Smux unlink(lockfile); 308156230Smux flock(lockfd, LOCK_UN); 309156230Smux close(lockfd); 310156230Smux } 311156230Smux config_free(config); 312156230Smux if (status != STATUS_SUCCESS) 313156230Smux return (1); 314156230Smux return (0); 315156230Smux} 316