1 1.135 lukem /* $NetBSD: main.c,v 1.135 2024/11/29 07:24:04 lukem Exp $ */ 2 1.59 lukem 3 1.59 lukem /*- 4 1.134 lukem * Copyright (c) 1996-2024 The NetBSD Foundation, Inc. 5 1.59 lukem * All rights reserved. 6 1.59 lukem * 7 1.59 lukem * This code is derived from software contributed to The NetBSD Foundation 8 1.59 lukem * by Luke Mewburn. 9 1.59 lukem * 10 1.59 lukem * Redistribution and use in source and binary forms, with or without 11 1.59 lukem * modification, are permitted provided that the following conditions 12 1.59 lukem * are met: 13 1.59 lukem * 1. Redistributions of source code must retain the above copyright 14 1.59 lukem * notice, this list of conditions and the following disclaimer. 15 1.59 lukem * 2. Redistributions in binary form must reproduce the above copyright 16 1.59 lukem * notice, this list of conditions and the following disclaimer in the 17 1.59 lukem * documentation and/or other materials provided with the distribution. 18 1.59 lukem * 19 1.59 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.59 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.59 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.59 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.59 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.59 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.59 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.59 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.59 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.59 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.59 lukem * POSSIBILITY OF SUCH DAMAGE. 30 1.59 lukem */ 31 1.45 itojun 32 1.45 itojun /* 33 1.55 lukem * Copyright (c) 1985, 1989, 1993, 1994 34 1.55 lukem * The Regents of the University of California. All rights reserved. 35 1.55 lukem * 36 1.45 itojun * Redistribution and use in source and binary forms, with or without 37 1.45 itojun * modification, are permitted provided that the following conditions 38 1.45 itojun * are met: 39 1.45 itojun * 1. Redistributions of source code must retain the above copyright 40 1.45 itojun * notice, this list of conditions and the following disclaimer. 41 1.45 itojun * 2. Redistributions in binary form must reproduce the above copyright 42 1.45 itojun * notice, this list of conditions and the following disclaimer in the 43 1.45 itojun * documentation and/or other materials provided with the distribution. 44 1.86 agc * 3. Neither the name of the University nor the names of its contributors 45 1.45 itojun * may be used to endorse or promote products derived from this software 46 1.45 itojun * without specific prior written permission. 47 1.55 lukem * 48 1.55 lukem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.45 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.45 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.55 lukem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.45 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.45 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.45 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.45 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.45 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.45 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.45 itojun * SUCH DAMAGE. 59 1.45 itojun */ 60 1.12 lukem 61 1.1 cgd /* 62 1.55 lukem * Copyright (C) 1997 and 1998 WIDE Project. 63 1.55 lukem * All rights reserved. 64 1.91 lukem * 65 1.1 cgd * Redistribution and use in source and binary forms, with or without 66 1.1 cgd * modification, are permitted provided that the following conditions 67 1.1 cgd * are met: 68 1.1 cgd * 1. Redistributions of source code must retain the above copyright 69 1.1 cgd * notice, this list of conditions and the following disclaimer. 70 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 71 1.1 cgd * notice, this list of conditions and the following disclaimer in the 72 1.1 cgd * documentation and/or other materials provided with the distribution. 73 1.55 lukem * 3. Neither the name of the project nor the names of its contributors 74 1.1 cgd * may be used to endorse or promote products derived from this software 75 1.1 cgd * without specific prior written permission. 76 1.91 lukem * 77 1.55 lukem * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 78 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 79 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 80 1.55 lukem * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 81 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 82 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 83 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 84 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 85 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 86 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 87 1.1 cgd * SUCH DAMAGE. 88 1.1 cgd */ 89 1.1 cgd 90 1.23 lukem #include <sys/cdefs.h> 91 1.1 cgd #ifndef lint 92 1.110 lukem __COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\ 93 1.111 lukem The Regents of the University of California. All rights reserved.\ 94 1.123 lukem Copyright 1996-2015 The NetBSD Foundation, Inc. All rights reserved"); 95 1.1 cgd #endif /* not lint */ 96 1.1 cgd 97 1.1 cgd #ifndef lint 98 1.8 tls #if 0 99 1.8 tls static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94"; 100 1.8 tls #else 101 1.135 lukem __RCSID("$NetBSD: main.c,v 1.135 2024/11/29 07:24:04 lukem Exp $"); 102 1.8 tls #endif 103 1.1 cgd #endif /* not lint */ 104 1.1 cgd 105 1.1 cgd /* 106 1.1 cgd * FTP User Program -- Command Interface. 107 1.1 cgd */ 108 1.3 cgd #include <sys/types.h> 109 1.1 cgd #include <sys/socket.h> 110 1.1 cgd 111 1.3 cgd #include <err.h> 112 1.61 lukem #include <errno.h> 113 1.1 cgd #include <netdb.h> 114 1.56 lukem #include <paths.h> 115 1.1 cgd #include <pwd.h> 116 1.90 lukem #include <signal.h> 117 1.3 cgd #include <stdio.h> 118 1.22 lukem #include <stdlib.h> 119 1.9 cgd #include <string.h> 120 1.105 lukem #include <time.h> 121 1.3 cgd #include <unistd.h> 122 1.76 jdolecek #include <locale.h> 123 1.1 cgd 124 1.57 lukem #define GLOBAL /* force GLOBAL decls in ftp_var.h to be declared */ 125 1.3 cgd #include "ftp_var.h" 126 1.1 cgd 127 1.65 lukem #define FTP_PROXY "ftp_proxy" /* env var with FTP proxy location */ 128 1.65 lukem #define HTTP_PROXY "http_proxy" /* env var with HTTP proxy location */ 129 1.122 christos #define HTTPS_PROXY "https_proxy" /* env var with HTTPS proxy location */ 130 1.65 lukem #define NO_PROXY "no_proxy" /* env var with list of non-proxied 131 1.35 lukem * hosts, comma or space separated */ 132 1.35 lukem 133 1.127 lukem static int usage(void); 134 1.127 lukem static int usage_help(void); 135 1.115 lukem static void setupoption(const char *, const char *, const char *); 136 1.23 lukem 137 1.132 christos struct http_headers custom_headers; 138 1.132 christos 139 1.3 cgd int 140 1.102 christos main(int volatile argc, char **volatile argv) 141 1.1 cgd { 142 1.64 lukem int ch, rval; 143 1.74 lukem struct passwd *pw; 144 1.132 christos struct entry *p; 145 1.115 lukem char *cp, *ep, *anonpass, *upload_path, *src_addr; 146 1.115 lukem const char *anonuser; 147 1.120 lukem int dumbterm, isupload; 148 1.95 lukem size_t len; 149 1.76 jdolecek 150 1.105 lukem tzset(); 151 1.76 jdolecek setlocale(LC_ALL, ""); 152 1.82 lukem setprogname(argv[0]); 153 1.1 cgd 154 1.90 lukem sigint_raised = 0; 155 1.90 lukem 156 1.45 itojun ftpport = "ftp"; 157 1.45 itojun httpport = "http"; 158 1.121 christos #ifdef WITH_SSL 159 1.121 christos httpsport = "https"; 160 1.121 christos #endif 161 1.45 itojun gateport = NULL; 162 1.24 lukem cp = getenv("FTPSERVERPORT"); 163 1.45 itojun if (cp != NULL) 164 1.45 itojun gateport = cp; 165 1.45 itojun else 166 1.45 itojun gateport = "ftpgate"; 167 1.1 cgd doglob = 1; 168 1.1 cgd interactive = 1; 169 1.1 cgd autologin = 1; 170 1.31 lukem passivemode = 1; 171 1.31 lukem activefallback = 1; 172 1.13 lukem preserve = 1; 173 1.17 lukem verbose = 0; 174 1.17 lukem progress = 0; 175 1.24 lukem gatemode = 0; 176 1.57 lukem data = -1; 177 1.39 lukem outfile = NULL; 178 1.39 lukem restartautofetch = 0; 179 1.43 cgd #ifndef NO_EDITCOMPLETE 180 1.18 lukem editing = 0; 181 1.21 lukem el = NULL; 182 1.21 lukem hist = NULL; 183 1.18 lukem #endif 184 1.60 lukem bytes = 0; 185 1.12 lukem mark = HASHBYTES; 186 1.44 lukem rate_get = 0; 187 1.44 lukem rate_get_incr = DEFAULTINCR; 188 1.44 lukem rate_put = 0; 189 1.44 lukem rate_put_incr = DEFAULTINCR; 190 1.49 lukem #ifdef INET6 191 1.47 itojun epsv4 = 1; 192 1.109 skd epsv6 = 1; 193 1.49 lukem #else 194 1.49 lukem epsv4 = 0; 195 1.109 skd epsv6 = 0; 196 1.49 lukem #endif 197 1.58 lukem epsv4bad = 0; 198 1.109 skd epsv6bad = 0; 199 1.104 lukem src_addr = NULL; 200 1.71 lukem upload_path = NULL; 201 1.71 lukem isupload = 0; 202 1.73 lukem reply_callback = NULL; 203 1.112 lukem #ifdef INET6 204 1.78 lukem family = AF_UNSPEC; 205 1.112 lukem #else 206 1.112 lukem family = AF_INET; /* force AF_INET if no INET6 support */ 207 1.112 lukem #endif 208 1.50 lukem 209 1.74 lukem netrc[0] = '\0'; 210 1.74 lukem cp = getenv("NETRC"); 211 1.74 lukem if (cp != NULL && strlcpy(netrc, cp, sizeof(netrc)) >= sizeof(netrc)) 212 1.74 lukem errx(1, "$NETRC `%s': %s", cp, strerror(ENAMETOOLONG)); 213 1.74 lukem 214 1.100 christos marg_sl = ftp_sl_init(); 215 1.25 lukem if ((tmpdir = getenv("TMPDIR")) == NULL) 216 1.25 lukem tmpdir = _PATH_TMP; 217 1.3 cgd 218 1.31 lukem /* Set default operation mode based on FTPMODE environment variable */ 219 1.31 lukem if ((cp = getenv("FTPMODE")) != NULL) { 220 1.65 lukem if (strcasecmp(cp, "passive") == 0) { 221 1.31 lukem passivemode = 1; 222 1.31 lukem activefallback = 0; 223 1.65 lukem } else if (strcasecmp(cp, "active") == 0) { 224 1.31 lukem passivemode = 0; 225 1.31 lukem activefallback = 0; 226 1.65 lukem } else if (strcasecmp(cp, "gate") == 0) { 227 1.31 lukem gatemode = 1; 228 1.65 lukem } else if (strcasecmp(cp, "auto") == 0) { 229 1.31 lukem passivemode = 1; 230 1.31 lukem activefallback = 1; 231 1.31 lukem } else 232 1.104 lukem warnx("Unknown $FTPMODE `%s'; using defaults", cp); 233 1.31 lukem } 234 1.31 lukem 235 1.77 cgd if (strcmp(getprogname(), "pftp") == 0) { 236 1.15 lukem passivemode = 1; 237 1.31 lukem activefallback = 0; 238 1.77 cgd } else if (strcmp(getprogname(), "gate-ftp") == 0) 239 1.24 lukem gatemode = 1; 240 1.24 lukem 241 1.24 lukem gateserver = getenv("FTPSERVER"); 242 1.24 lukem if (gateserver == NULL || *gateserver == '\0') 243 1.24 lukem gateserver = GATE_SERVER; 244 1.24 lukem if (gatemode) { 245 1.24 lukem if (*gateserver == '\0') { 246 1.24 lukem warnx( 247 1.42 lukem "Neither $FTPSERVER nor GATE_SERVER is defined; disabling gate-ftp"); 248 1.24 lukem gatemode = 0; 249 1.24 lukem } 250 1.24 lukem } 251 1.15 lukem 252 1.22 lukem cp = getenv("TERM"); 253 1.22 lukem if (cp == NULL || strcmp(cp, "dumb") == 0) 254 1.22 lukem dumbterm = 1; 255 1.22 lukem else 256 1.22 lukem dumbterm = 0; 257 1.17 lukem fromatty = isatty(fileno(stdin)); 258 1.37 lukem ttyout = stdout; 259 1.37 lukem if (isatty(fileno(ttyout))) { 260 1.41 lukem verbose = 1; /* verbose if to a tty */ 261 1.37 lukem if (! dumbterm) { 262 1.43 cgd #ifndef NO_EDITCOMPLETE 263 1.41 lukem if (fromatty) /* editing mode on if tty is usable */ 264 1.41 lukem editing = 1; 265 1.43 cgd #endif 266 1.43 cgd #ifndef NO_PROGRESS 267 1.37 lukem if (foregroundproc()) 268 1.37 lukem progress = 1; /* progress bar on if fg */ 269 1.43 cgd #endif 270 1.37 lukem } 271 1.18 lukem } 272 1.17 lukem 273 1.132 christos SLIST_INIT(&custom_headers); 274 1.135 lukem while ((ch = getopt(argc, argv, ":46Aab:defgH:iN:no:P:pq:Rr:s:T:tu:Vvx:")) != -1) { 275 1.6 mycroft switch (ch) { 276 1.78 lukem case '4': 277 1.78 lukem family = AF_INET; 278 1.78 lukem break; 279 1.78 lukem 280 1.78 lukem case '6': 281 1.82 lukem #ifdef INET6 282 1.78 lukem family = AF_INET6; 283 1.82 lukem #else 284 1.82 lukem warnx("INET6 support is not available; ignoring -6"); 285 1.82 lukem #endif 286 1.78 lukem break; 287 1.78 lukem 288 1.31 lukem case 'A': 289 1.31 lukem activefallback = 0; 290 1.31 lukem passivemode = 0; 291 1.31 lukem break; 292 1.31 lukem 293 1.12 lukem case 'a': 294 1.12 lukem anonftp = 1; 295 1.12 lukem break; 296 1.12 lukem 297 1.130 christos case 'b': 298 1.130 christos ftp_buflen = strtol(optarg, &ep, 0); 299 1.130 christos if (ftp_buflen < 1 || *ep != '\0') 300 1.130 christos errx(1, "Bad buflen value: %s", optarg); 301 1.130 christos break; 302 1.130 christos 303 1.3 cgd case 'd': 304 1.3 cgd options |= SO_DEBUG; 305 1.101 christos ftp_debug++; 306 1.3 cgd break; 307 1.12 lukem 308 1.18 lukem case 'e': 309 1.43 cgd #ifndef NO_EDITCOMPLETE 310 1.18 lukem editing = 0; 311 1.18 lukem #endif 312 1.18 lukem break; 313 1.18 lukem 314 1.36 lukem case 'f': 315 1.36 lukem flushcache = 1; 316 1.36 lukem break; 317 1.36 lukem 318 1.3 cgd case 'g': 319 1.3 cgd doglob = 0; 320 1.3 cgd break; 321 1.1 cgd 322 1.132 christos case 'H': 323 1.132 christos p = ftp_malloc(sizeof(*p)); 324 1.132 christos p->header = ftp_strdup(optarg); 325 1.132 christos SLIST_INSERT_HEAD(&custom_headers, p, entries); 326 1.132 christos break; 327 1.132 christos 328 1.3 cgd case 'i': 329 1.3 cgd interactive = 0; 330 1.3 cgd break; 331 1.1 cgd 332 1.74 lukem case 'N': 333 1.74 lukem if (strlcpy(netrc, optarg, sizeof(netrc)) 334 1.74 lukem >= sizeof(netrc)) 335 1.74 lukem errx(1, "%s: %s", optarg, 336 1.74 lukem strerror(ENAMETOOLONG)); 337 1.74 lukem break; 338 1.74 lukem 339 1.135 lukem case 'n': 340 1.135 lukem autologin = 0; 341 1.135 lukem break; 342 1.135 lukem 343 1.31 lukem case 'o': 344 1.124 christos outfile = ftp_strdup(optarg); 345 1.31 lukem if (strcmp(outfile, "-") == 0) 346 1.31 lukem ttyout = stderr; 347 1.31 lukem break; 348 1.31 lukem 349 1.135 lukem case 'P': 350 1.135 lukem ftpport = optarg; 351 1.135 lukem break; 352 1.135 lukem 353 1.12 lukem case 'p': 354 1.12 lukem passivemode = 1; 355 1.31 lukem activefallback = 0; 356 1.12 lukem break; 357 1.12 lukem 358 1.83 christos case 'q': 359 1.131 christos quit_time = (int)strtol(optarg, &ep, 10); 360 1.83 christos if (quit_time < 1 || *ep != '\0') 361 1.104 lukem errx(1, "Bad quit value: %s", optarg); 362 1.12 lukem break; 363 1.12 lukem 364 1.135 lukem case 'R': 365 1.135 lukem restartautofetch = 1; 366 1.135 lukem break; 367 1.135 lukem 368 1.31 lukem case 'r': 369 1.131 christos retry_connect = (int)strtol(optarg, &ep, 10); 370 1.39 lukem if (retry_connect < 1 || *ep != '\0') 371 1.104 lukem errx(1, "Bad retry value: %s", optarg); 372 1.31 lukem break; 373 1.31 lukem 374 1.104 lukem case 's': 375 1.104 lukem src_addr = optarg; 376 1.104 lukem break; 377 1.104 lukem 378 1.44 lukem case 'T': 379 1.44 lukem { 380 1.44 lukem int targc; 381 1.44 lukem char *targv[6], *oac; 382 1.115 lukem char cmdbuf[MAX_C_NAME]; 383 1.44 lukem 384 1.44 lukem /* look for `dir,max[,incr]' */ 385 1.44 lukem targc = 0; 386 1.115 lukem (void)strlcpy(cmdbuf, "-T", sizeof(cmdbuf)); 387 1.115 lukem targv[targc++] = cmdbuf; 388 1.100 christos oac = ftp_strdup(optarg); 389 1.44 lukem 390 1.44 lukem while ((cp = strsep(&oac, ",")) != NULL) { 391 1.44 lukem if (*cp == '\0') { 392 1.104 lukem warnx("Bad throttle value `%s'", 393 1.104 lukem optarg); 394 1.127 lukem return usage(); 395 1.44 lukem } 396 1.44 lukem targv[targc++] = cp; 397 1.44 lukem if (targc >= 5) 398 1.44 lukem break; 399 1.44 lukem } 400 1.127 lukem if (parserate(targc, targv, 1) == -1) { 401 1.127 lukem return usage(); 402 1.127 lukem } 403 1.44 lukem free(oac); 404 1.44 lukem break; 405 1.44 lukem } 406 1.44 lukem 407 1.135 lukem case 't': 408 1.135 lukem trace = 1; 409 1.135 lukem break; 410 1.135 lukem 411 1.71 lukem case 'u': 412 1.71 lukem { 413 1.71 lukem isupload = 1; 414 1.71 lukem interactive = 0; 415 1.100 christos upload_path = ftp_strdup(optarg); 416 1.71 lukem 417 1.71 lukem break; 418 1.71 lukem } 419 1.71 lukem 420 1.135 lukem case 'V': 421 1.135 lukem progress = verbose = 0; 422 1.135 lukem break; 423 1.135 lukem 424 1.3 cgd case 'v': 425 1.37 lukem progress = verbose = 1; 426 1.17 lukem break; 427 1.17 lukem 428 1.123 lukem case 'x': 429 1.123 lukem sndbuf_size = strsuftoi(optarg); 430 1.123 lukem if (sndbuf_size < 1) 431 1.123 lukem errx(1, "Bad xferbuf value: %s", optarg); 432 1.123 lukem rcvbuf_size = sndbuf_size; 433 1.123 lukem break; 434 1.123 lukem 435 1.127 lukem case '?': 436 1.127 lukem if (optopt == '?') { 437 1.127 lukem return usage_help(); 438 1.127 lukem } 439 1.128 lukem warnx("-%c: unknown option", optopt); 440 1.128 lukem return usage(); 441 1.128 lukem 442 1.128 lukem case ':': 443 1.128 lukem warnx("-%c: missing argument", optopt); 444 1.127 lukem return usage(); 445 1.127 lukem 446 1.3 cgd default: 447 1.127 lukem errx(1, "unimplemented option -%c", ch); 448 1.3 cgd } 449 1.1 cgd } 450 1.37 lukem /* set line buffering on ttyout */ 451 1.37 lukem setvbuf(ttyout, NULL, _IOLBF, 0); 452 1.3 cgd argc -= optind; 453 1.3 cgd argv += optind; 454 1.3 cgd 455 1.1 cgd cpend = 0; /* no pending replies */ 456 1.1 cgd proxy = 0; /* proxy not active */ 457 1.1 cgd crflag = 1; /* strip c.r. on ascii gets */ 458 1.1 cgd sendport = -1; /* not using ports */ 459 1.74 lukem 460 1.104 lukem if (src_addr != NULL) { 461 1.104 lukem struct addrinfo hints; 462 1.104 lukem int error; 463 1.104 lukem 464 1.104 lukem memset(&hints, 0, sizeof(hints)); 465 1.104 lukem hints.ai_family = family; 466 1.104 lukem hints.ai_socktype = SOCK_STREAM; 467 1.104 lukem hints.ai_flags = AI_PASSIVE; 468 1.104 lukem error = getaddrinfo(src_addr, NULL, &hints, &bindai); 469 1.104 lukem if (error) { 470 1.104 lukem errx(1, "Can't lookup `%s': %s", src_addr, 471 1.104 lukem (error == EAI_SYSTEM) ? strerror(errno) 472 1.104 lukem : gai_strerror(error)); 473 1.104 lukem } 474 1.104 lukem } 475 1.104 lukem 476 1.1 cgd /* 477 1.74 lukem * Cache the user name and home directory. 478 1.1 cgd */ 479 1.74 lukem localhome = NULL; 480 1.74 lukem localname = NULL; 481 1.74 lukem anonuser = "anonymous"; 482 1.74 lukem cp = getenv("HOME"); 483 1.74 lukem if (! EMPTYSTRING(cp)) 484 1.100 christos localhome = ftp_strdup(cp); 485 1.74 lukem pw = NULL; 486 1.1 cgd cp = getlogin(); 487 1.65 lukem if (cp != NULL) 488 1.1 cgd pw = getpwnam(cp); 489 1.1 cgd if (pw == NULL) 490 1.1 cgd pw = getpwuid(getuid()); 491 1.65 lukem if (pw != NULL) { 492 1.74 lukem if (localhome == NULL && !EMPTYSTRING(pw->pw_dir)) 493 1.100 christos localhome = ftp_strdup(pw->pw_dir); 494 1.100 christos localname = ftp_strdup(pw->pw_name); 495 1.74 lukem } 496 1.74 lukem if (netrc[0] == '\0' && localhome != NULL) { 497 1.74 lukem if (strlcpy(netrc, localhome, sizeof(netrc)) >= sizeof(netrc) || 498 1.91 lukem strlcat(netrc, "/.netrc", sizeof(netrc)) >= sizeof(netrc)) { 499 1.74 lukem warnx("%s/.netrc: %s", localhome, 500 1.74 lukem strerror(ENAMETOOLONG)); 501 1.74 lukem netrc[0] = '\0'; 502 1.74 lukem } 503 1.65 lukem } 504 1.74 lukem if (localhome == NULL) 505 1.100 christos localhome = ftp_strdup("/"); 506 1.65 lukem 507 1.65 lukem /* 508 1.65 lukem * Every anonymous FTP server I've encountered will accept the 509 1.65 lukem * string "username@", and will append the hostname itself. We 510 1.65 lukem * do this by default since many servers are picky about not 511 1.65 lukem * having a FQDN in the anonymous password. 512 1.85 salo * - thorpej (at) NetBSD.org 513 1.65 lukem */ 514 1.65 lukem len = strlen(anonuser) + 2; 515 1.100 christos anonpass = ftp_malloc(len); 516 1.65 lukem (void)strlcpy(anonpass, anonuser, len); 517 1.65 lukem (void)strlcat(anonpass, "@", len); 518 1.65 lukem 519 1.67 lukem /* 520 1.67 lukem * set all the defaults for options defined in 521 1.67 lukem * struct option optiontab[] declared in cmdtab.c 522 1.67 lukem */ 523 1.65 lukem setupoption("anonpass", getenv("FTPANONPASS"), anonpass); 524 1.66 lukem setupoption("ftp_proxy", getenv(FTP_PROXY), ""); 525 1.66 lukem setupoption("http_proxy", getenv(HTTP_PROXY), ""); 526 1.122 christos setupoption("https_proxy", getenv(HTTPS_PROXY), ""); 527 1.66 lukem setupoption("no_proxy", getenv(NO_PROXY), ""); 528 1.66 lukem setupoption("pager", getenv("PAGER"), DEFAULTPAGER); 529 1.67 lukem setupoption("prompt", getenv("FTPPROMPT"), DEFAULTPROMPT); 530 1.67 lukem setupoption("rprompt", getenv("FTPRPROMPT"), DEFAULTRPROMPT); 531 1.129 mlelstv setupoption("sslnoverify", getenv("FTPSSLNOVERIFY"), ""); 532 1.66 lukem 533 1.66 lukem free(anonpass); 534 1.12 lukem 535 1.17 lukem setttywidth(0); 536 1.60 lukem #ifdef SIGINFO 537 1.60 lukem (void)xsignal(SIGINFO, psummary); 538 1.60 lukem #endif 539 1.60 lukem (void)xsignal(SIGQUIT, psummary); 540 1.44 lukem (void)xsignal(SIGUSR1, crankrate); 541 1.44 lukem (void)xsignal(SIGUSR2, crankrate); 542 1.60 lukem (void)xsignal(SIGWINCH, setttywidth); 543 1.23 lukem 544 1.1 cgd if (argc > 0) { 545 1.71 lukem if (isupload) { 546 1.71 lukem rval = auto_put(argc, argv, upload_path); 547 1.90 lukem sigint_or_rval_exit: 548 1.90 lukem if (sigint_raised) { 549 1.90 lukem (void)xsignal(SIGINT, SIG_DFL); 550 1.90 lukem raise(SIGINT); 551 1.90 lukem } 552 1.71 lukem exit(rval); 553 1.71 lukem } else if (strchr(argv[0], ':') != NULL 554 1.71 lukem && ! isipv6addr(argv[0])) { 555 1.39 lukem rval = auto_fetch(argc, argv); 556 1.16 lukem if (rval >= 0) /* -1 == connected and cd-ed */ 557 1.90 lukem goto sigint_or_rval_exit; 558 1.16 lukem } else { 559 1.114 lukem char *xargv[4], *uuser, *host; 560 1.115 lukem char cmdbuf[MAXPATHLEN]; 561 1.3 cgd 562 1.90 lukem if ((rval = sigsetjmp(toplevel, 1))) 563 1.90 lukem goto sigint_or_rval_exit; 564 1.61 lukem (void)xsignal(SIGINT, intr); 565 1.65 lukem (void)xsignal(SIGPIPE, lostpeer); 566 1.114 lukem uuser = NULL; 567 1.68 lukem host = argv[0]; 568 1.68 lukem cp = strchr(host, '@'); 569 1.68 lukem if (cp) { 570 1.68 lukem *cp = '\0'; 571 1.114 lukem uuser = host; 572 1.68 lukem host = cp + 1; 573 1.68 lukem } 574 1.115 lukem (void)strlcpy(cmdbuf, getprogname(), sizeof(cmdbuf)); 575 1.115 lukem xargv[0] = cmdbuf; 576 1.68 lukem xargv[1] = host; 577 1.16 lukem xargv[2] = argv[1]; 578 1.68 lukem xargv[3] = NULL; 579 1.31 lukem do { 580 1.68 lukem int oautologin; 581 1.68 lukem 582 1.68 lukem oautologin = autologin; 583 1.114 lukem if (uuser != NULL) { 584 1.68 lukem anonftp = 0; 585 1.68 lukem autologin = 0; 586 1.68 lukem } 587 1.116 lukem setpeer(argc+1, xargv); 588 1.68 lukem autologin = oautologin; 589 1.114 lukem if (connected == 1 && uuser != NULL) 590 1.114 lukem (void)ftp_login(host, uuser, NULL); 591 1.31 lukem if (!retry_connect) 592 1.31 lukem break; 593 1.31 lukem if (!connected) { 594 1.31 lukem macnum = 0; 595 1.31 lukem fprintf(ttyout, 596 1.31 lukem "Retrying in %d seconds...\n", 597 1.31 lukem retry_connect); 598 1.31 lukem sleep(retry_connect); 599 1.31 lukem } 600 1.31 lukem } while (!connected); 601 1.31 lukem retry_connect = 0; /* connected, stop hiding msgs */ 602 1.16 lukem } 603 1.1 cgd } 604 1.127 lukem if (isupload) { 605 1.127 lukem return usage(); 606 1.127 lukem } 607 1.71 lukem 608 1.43 cgd #ifndef NO_EDITCOMPLETE 609 1.21 lukem controlediting(); 610 1.43 cgd #endif /* !NO_EDITCOMPLETE */ 611 1.64 lukem 612 1.64 lukem (void)sigsetjmp(toplevel, 1); 613 1.64 lukem (void)xsignal(SIGINT, intr); 614 1.65 lukem (void)xsignal(SIGPIPE, lostpeer); 615 1.64 lukem for (;;) 616 1.64 lukem cmdscanner(); 617 1.1 cgd } 618 1.1 cgd 619 1.3 cgd /* 620 1.16 lukem * Generate a prompt 621 1.16 lukem */ 622 1.3 cgd char * 623 1.70 lukem prompt(void) 624 1.1 cgd { 625 1.114 lukem static char **promptopt; 626 1.66 lukem static char buf[MAXPATHLEN]; 627 1.66 lukem 628 1.114 lukem if (promptopt == NULL) { 629 1.66 lukem struct option *o; 630 1.66 lukem 631 1.66 lukem o = getoption("prompt"); 632 1.66 lukem if (o == NULL) 633 1.104 lukem errx(1, "prompt: no such option `prompt'"); 634 1.114 lukem promptopt = &(o->value); 635 1.66 lukem } 636 1.114 lukem formatbuf(buf, sizeof(buf), *promptopt ? *promptopt : DEFAULTPROMPT); 637 1.67 lukem return (buf); 638 1.67 lukem } 639 1.67 lukem 640 1.67 lukem /* 641 1.67 lukem * Generate an rprompt 642 1.67 lukem */ 643 1.67 lukem char * 644 1.70 lukem rprompt(void) 645 1.67 lukem { 646 1.114 lukem static char **rpromptopt; 647 1.67 lukem static char buf[MAXPATHLEN]; 648 1.67 lukem 649 1.114 lukem if (rpromptopt == NULL) { 650 1.67 lukem struct option *o; 651 1.66 lukem 652 1.67 lukem o = getoption("rprompt"); 653 1.67 lukem if (o == NULL) 654 1.104 lukem errx(1, "rprompt: no such option `rprompt'"); 655 1.114 lukem rpromptopt = &(o->value); 656 1.66 lukem } 657 1.114 lukem formatbuf(buf, sizeof(buf), *rpromptopt ? *rpromptopt : DEFAULTRPROMPT); 658 1.66 lukem return (buf); 659 1.1 cgd } 660 1.3 cgd 661 1.1 cgd /* 662 1.1 cgd * Command parser. 663 1.1 cgd */ 664 1.3 cgd void 665 1.70 lukem cmdscanner(void) 666 1.1 cgd { 667 1.67 lukem struct cmd *c; 668 1.67 lukem char *p; 669 1.98 jmc #ifndef NO_EDITCOMPLETE 670 1.95 lukem int ch; 671 1.113 gmcgarry size_t num; 672 1.98 jmc #endif 673 1.113 gmcgarry int len; 674 1.115 lukem char cmdbuf[MAX_C_NAME]; 675 1.1 cgd 676 1.1 cgd for (;;) { 677 1.43 cgd #ifndef NO_EDITCOMPLETE 678 1.16 lukem if (!editing) { 679 1.43 cgd #endif /* !NO_EDITCOMPLETE */ 680 1.16 lukem if (fromatty) { 681 1.31 lukem fputs(prompt(), ttyout); 682 1.67 lukem p = rprompt(); 683 1.67 lukem if (*p) 684 1.67 lukem fprintf(ttyout, "%s ", p); 685 1.16 lukem } 686 1.103 lukem (void)fflush(ttyout); 687 1.117 roy len = get_line(stdin, line, sizeof(line), NULL); 688 1.113 gmcgarry switch (len) { 689 1.97 lukem case -1: /* EOF */ 690 1.97 lukem case -2: /* error */ 691 1.63 lukem if (fromatty) 692 1.63 lukem putc('\n', ttyout); 693 1.126 mrg justquit(); 694 1.97 lukem /* NOTREACHED */ 695 1.97 lukem case -3: /* too long; try again */ 696 1.92 lukem fputs("Sorry, input line is too long.\n", 697 1.92 lukem ttyout); 698 1.97 lukem continue; 699 1.97 lukem case 0: /* empty; try again */ 700 1.97 lukem continue; 701 1.97 lukem default: /* all ok */ 702 1.16 lukem break; 703 1.97 lukem } 704 1.43 cgd #ifndef NO_EDITCOMPLETE 705 1.17 lukem } else { 706 1.16 lukem const char *buf; 707 1.26 christos HistEvent ev; 708 1.16 lukem cursor_pos = NULL; 709 1.16 lukem 710 1.96 jdc buf = el_gets(el, &ch); 711 1.96 jdc num = ch; 712 1.92 lukem if (buf == NULL || num == 0) { 713 1.63 lukem if (fromatty) 714 1.63 lukem putc('\n', ttyout); 715 1.126 mrg justquit(); 716 1.63 lukem } 717 1.92 lukem if (num >= sizeof(line)) { 718 1.92 lukem fputs("Sorry, input line is too long.\n", 719 1.92 lukem ttyout); 720 1.92 lukem break; 721 1.92 lukem } 722 1.92 lukem memcpy(line, buf, num); 723 1.92 lukem if (line[--num] == '\n') { 724 1.92 lukem line[num] = '\0'; 725 1.16 lukem if (num == 0) 726 1.16 lukem break; 727 1.16 lukem } 728 1.26 christos history(hist, &ev, H_ENTER, buf); 729 1.16 lukem } 730 1.43 cgd #endif /* !NO_EDITCOMPLETE */ 731 1.16 lukem 732 1.1 cgd makeargv(); 733 1.16 lukem if (margc == 0) 734 1.1 cgd continue; 735 1.1 cgd c = getcmd(margv[0]); 736 1.1 cgd if (c == (struct cmd *)-1) { 737 1.31 lukem fputs("?Ambiguous command.\n", ttyout); 738 1.1 cgd continue; 739 1.1 cgd } 740 1.30 lukem if (c == NULL) { 741 1.43 cgd #if !defined(NO_EDITCOMPLETE) 742 1.30 lukem /* 743 1.30 lukem * attempt to el_parse() unknown commands. 744 1.30 lukem * any command containing a ':' would be parsed 745 1.30 lukem * as "[prog:]cmd ...", and will result in a 746 1.30 lukem * false positive if prog != "ftp", so treat 747 1.30 lukem * such commands as invalid. 748 1.30 lukem */ 749 1.38 lukem if (strchr(margv[0], ':') != NULL || 750 1.108 lukem !editing || 751 1.118 christos el_parse(el, margc, (void *)margv) != 0) 752 1.43 cgd #endif /* !NO_EDITCOMPLETE */ 753 1.31 lukem fputs("?Invalid command.\n", ttyout); 754 1.1 cgd continue; 755 1.1 cgd } 756 1.1 cgd if (c->c_conn && !connected) { 757 1.31 lukem fputs("Not connected.\n", ttyout); 758 1.1 cgd continue; 759 1.1 cgd } 760 1.13 lukem confirmrest = 0; 761 1.115 lukem (void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf)); 762 1.115 lukem margv[0] = cmdbuf; 763 1.1 cgd (*c->c_handler)(margc, margv); 764 1.1 cgd if (bell && c->c_bell) 765 1.31 lukem (void)putc('\007', ttyout); 766 1.1 cgd if (c->c_handler != help) 767 1.1 cgd break; 768 1.1 cgd } 769 1.61 lukem (void)xsignal(SIGINT, intr); 770 1.65 lukem (void)xsignal(SIGPIPE, lostpeer); 771 1.1 cgd } 772 1.1 cgd 773 1.1 cgd struct cmd * 774 1.70 lukem getcmd(const char *name) 775 1.1 cgd { 776 1.13 lukem const char *p, *q; 777 1.3 cgd struct cmd *c, *found; 778 1.131 christos int nmatches; 779 1.131 christos ptrdiff_t longest; 780 1.11 pk 781 1.11 pk if (name == NULL) 782 1.11 pk return (0); 783 1.1 cgd 784 1.1 cgd longest = 0; 785 1.1 cgd nmatches = 0; 786 1.1 cgd found = 0; 787 1.12 lukem for (c = cmdtab; (p = c->c_name) != NULL; c++) { 788 1.1 cgd for (q = name; *q == *p++; q++) 789 1.1 cgd if (*q == 0) /* exact match? */ 790 1.1 cgd return (c); 791 1.1 cgd if (!*q) { /* the name was a prefix */ 792 1.1 cgd if (q - name > longest) { 793 1.1 cgd longest = q - name; 794 1.1 cgd nmatches = 1; 795 1.1 cgd found = c; 796 1.1 cgd } else if (q - name == longest) 797 1.1 cgd nmatches++; 798 1.1 cgd } 799 1.1 cgd } 800 1.1 cgd if (nmatches > 1) 801 1.1 cgd return ((struct cmd *)-1); 802 1.1 cgd return (found); 803 1.1 cgd } 804 1.1 cgd 805 1.1 cgd /* 806 1.1 cgd * Slice a string up into argc/argv. 807 1.1 cgd */ 808 1.1 cgd 809 1.131 christos static int slrflag; 810 1.1 cgd 811 1.3 cgd void 812 1.70 lukem makeargv(void) 813 1.1 cgd { 814 1.16 lukem char *argp; 815 1.1 cgd 816 1.1 cgd stringbase = line; /* scan from first of buffer */ 817 1.1 cgd argbase = argbuf; /* store from first of buffer */ 818 1.1 cgd slrflag = 0; 819 1.16 lukem marg_sl->sl_cur = 0; /* reset to start of marg_sl */ 820 1.10 pk for (margc = 0; ; margc++) { 821 1.16 lukem argp = slurpstring(); 822 1.100 christos ftp_sl_add(marg_sl, argp); 823 1.16 lukem if (argp == NULL) 824 1.10 pk break; 825 1.10 pk } 826 1.43 cgd #ifndef NO_EDITCOMPLETE 827 1.16 lukem if (cursor_pos == line) { 828 1.16 lukem cursor_argc = 0; 829 1.16 lukem cursor_argo = 0; 830 1.16 lukem } else if (cursor_pos != NULL) { 831 1.16 lukem cursor_argc = margc; 832 1.16 lukem cursor_argo = strlen(margv[margc-1]); 833 1.16 lukem } 834 1.43 cgd #endif /* !NO_EDITCOMPLETE */ 835 1.16 lukem } 836 1.10 pk 837 1.43 cgd #ifdef NO_EDITCOMPLETE 838 1.65 lukem #define INC_CHKCURSOR(x) (x)++ 839 1.43 cgd #else /* !NO_EDITCOMPLETE */ 840 1.65 lukem #define INC_CHKCURSOR(x) { (x)++ ; \ 841 1.16 lukem if (x == cursor_pos) { \ 842 1.16 lukem cursor_argc = margc; \ 843 1.16 lukem cursor_argo = ap-argbase; \ 844 1.16 lukem cursor_pos = NULL; \ 845 1.16 lukem } } 846 1.38 lukem 847 1.43 cgd #endif /* !NO_EDITCOMPLETE */ 848 1.1 cgd 849 1.1 cgd /* 850 1.1 cgd * Parse string into argbuf; 851 1.1 cgd * implemented with FSM to 852 1.1 cgd * handle quoting and strings 853 1.1 cgd */ 854 1.1 cgd char * 855 1.70 lukem slurpstring(void) 856 1.1 cgd { 857 1.115 lukem static char bangstr[2] = { '!', '\0' }; 858 1.115 lukem static char dollarstr[2] = { '$', '\0' }; 859 1.1 cgd int got_one = 0; 860 1.3 cgd char *sb = stringbase; 861 1.3 cgd char *ap = argbase; 862 1.1 cgd char *tmp = argbase; /* will return this if token found */ 863 1.1 cgd 864 1.1 cgd if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ 865 1.1 cgd switch (slrflag) { /* and $ as token for macro invoke */ 866 1.1 cgd case 0: 867 1.1 cgd slrflag++; 868 1.16 lukem INC_CHKCURSOR(stringbase); 869 1.115 lukem return ((*sb == '!') ? bangstr : dollarstr); 870 1.1 cgd case 1: 871 1.1 cgd slrflag++; 872 1.1 cgd altarg = stringbase; 873 1.1 cgd break; 874 1.1 cgd default: 875 1.1 cgd break; 876 1.1 cgd } 877 1.1 cgd } 878 1.1 cgd 879 1.1 cgd S0: 880 1.1 cgd switch (*sb) { 881 1.1 cgd 882 1.1 cgd case '\0': 883 1.1 cgd goto OUT; 884 1.1 cgd 885 1.1 cgd case ' ': 886 1.1 cgd case '\t': 887 1.16 lukem INC_CHKCURSOR(sb); 888 1.16 lukem goto S0; 889 1.1 cgd 890 1.1 cgd default: 891 1.1 cgd switch (slrflag) { 892 1.1 cgd case 0: 893 1.1 cgd slrflag++; 894 1.1 cgd break; 895 1.1 cgd case 1: 896 1.1 cgd slrflag++; 897 1.1 cgd altarg = sb; 898 1.1 cgd break; 899 1.1 cgd default: 900 1.1 cgd break; 901 1.1 cgd } 902 1.1 cgd goto S1; 903 1.1 cgd } 904 1.1 cgd 905 1.1 cgd S1: 906 1.1 cgd switch (*sb) { 907 1.1 cgd 908 1.1 cgd case ' ': 909 1.1 cgd case '\t': 910 1.1 cgd case '\0': 911 1.1 cgd goto OUT; /* end of token */ 912 1.1 cgd 913 1.1 cgd case '\\': 914 1.16 lukem INC_CHKCURSOR(sb); 915 1.16 lukem goto S2; /* slurp next character */ 916 1.1 cgd 917 1.1 cgd case '"': 918 1.16 lukem INC_CHKCURSOR(sb); 919 1.16 lukem goto S3; /* slurp quoted string */ 920 1.1 cgd 921 1.1 cgd default: 922 1.16 lukem *ap = *sb; /* add character to token */ 923 1.16 lukem ap++; 924 1.16 lukem INC_CHKCURSOR(sb); 925 1.1 cgd got_one = 1; 926 1.1 cgd goto S1; 927 1.1 cgd } 928 1.1 cgd 929 1.1 cgd S2: 930 1.1 cgd switch (*sb) { 931 1.1 cgd 932 1.1 cgd case '\0': 933 1.1 cgd goto OUT; 934 1.1 cgd 935 1.1 cgd default: 936 1.16 lukem *ap = *sb; 937 1.16 lukem ap++; 938 1.16 lukem INC_CHKCURSOR(sb); 939 1.1 cgd got_one = 1; 940 1.1 cgd goto S1; 941 1.1 cgd } 942 1.1 cgd 943 1.1 cgd S3: 944 1.1 cgd switch (*sb) { 945 1.1 cgd 946 1.1 cgd case '\0': 947 1.1 cgd goto OUT; 948 1.1 cgd 949 1.1 cgd case '"': 950 1.16 lukem INC_CHKCURSOR(sb); 951 1.16 lukem goto S1; 952 1.1 cgd 953 1.1 cgd default: 954 1.16 lukem *ap = *sb; 955 1.16 lukem ap++; 956 1.16 lukem INC_CHKCURSOR(sb); 957 1.1 cgd got_one = 1; 958 1.1 cgd goto S3; 959 1.1 cgd } 960 1.1 cgd 961 1.1 cgd OUT: 962 1.1 cgd if (got_one) 963 1.1 cgd *ap++ = '\0'; 964 1.1 cgd argbase = ap; /* update storage pointer */ 965 1.1 cgd stringbase = sb; /* update scan pointer */ 966 1.1 cgd if (got_one) { 967 1.3 cgd return (tmp); 968 1.1 cgd } 969 1.1 cgd switch (slrflag) { 970 1.1 cgd case 0: 971 1.1 cgd slrflag++; 972 1.1 cgd break; 973 1.1 cgd case 1: 974 1.1 cgd slrflag++; 975 1.28 lukem altarg = NULL; 976 1.1 cgd break; 977 1.1 cgd default: 978 1.1 cgd break; 979 1.1 cgd } 980 1.28 lukem return (NULL); 981 1.1 cgd } 982 1.1 cgd 983 1.1 cgd /* 984 1.65 lukem * Help/usage command. 985 1.1 cgd * Call each command handler with argc == 0 and argv[0] == name. 986 1.1 cgd */ 987 1.3 cgd void 988 1.70 lukem help(int argc, char *argv[]) 989 1.1 cgd { 990 1.3 cgd struct cmd *c; 991 1.115 lukem char *nargv[1], *cmd; 992 1.115 lukem const char *p; 993 1.65 lukem int isusage; 994 1.1 cgd 995 1.67 lukem cmd = argv[0]; 996 1.67 lukem isusage = (strcmp(cmd, "usage") == 0); 997 1.65 lukem if (argc == 0 || (isusage && argc == 1)) { 998 1.127 lukem UPRINTF("usage: %s [command ...]\n", cmd); 999 1.65 lukem return; 1000 1.65 lukem } 1001 1.1 cgd if (argc == 1) { 1002 1.16 lukem StringList *buf; 1003 1.1 cgd 1004 1.100 christos buf = ftp_sl_init(); 1005 1.31 lukem fprintf(ttyout, 1006 1.31 lukem "%sommands may be abbreviated. Commands are:\n\n", 1007 1.16 lukem proxy ? "Proxy c" : "C"); 1008 1.65 lukem for (c = cmdtab; (p = c->c_name) != NULL; c++) 1009 1.65 lukem if (!proxy || c->c_proxy) 1010 1.115 lukem ftp_sl_add(buf, ftp_strdup(p)); 1011 1.16 lukem list_vertical(buf); 1012 1.115 lukem sl_free(buf, 1); 1013 1.1 cgd return; 1014 1.1 cgd } 1015 1.16 lukem 1016 1.65 lukem #define HELPINDENT ((int) sizeof("disconnect")) 1017 1.16 lukem 1018 1.1 cgd while (--argc > 0) { 1019 1.3 cgd char *arg; 1020 1.115 lukem char cmdbuf[MAX_C_NAME]; 1021 1.16 lukem 1022 1.1 cgd arg = *++argv; 1023 1.1 cgd c = getcmd(arg); 1024 1.1 cgd if (c == (struct cmd *)-1) 1025 1.65 lukem fprintf(ttyout, "?Ambiguous %s command `%s'\n", 1026 1.67 lukem cmd, arg); 1027 1.28 lukem else if (c == NULL) 1028 1.65 lukem fprintf(ttyout, "?Invalid %s command `%s'\n", 1029 1.67 lukem cmd, arg); 1030 1.65 lukem else { 1031 1.65 lukem if (isusage) { 1032 1.115 lukem (void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf)); 1033 1.115 lukem nargv[0] = cmdbuf; 1034 1.65 lukem (*c->c_handler)(0, nargv); 1035 1.65 lukem } else 1036 1.65 lukem fprintf(ttyout, "%-*s\t%s\n", HELPINDENT, 1037 1.65 lukem c->c_name, c->c_help); 1038 1.65 lukem } 1039 1.1 cgd } 1040 1.65 lukem } 1041 1.65 lukem 1042 1.65 lukem struct option * 1043 1.70 lukem getoption(const char *name) 1044 1.65 lukem { 1045 1.65 lukem const char *p; 1046 1.65 lukem struct option *c; 1047 1.65 lukem 1048 1.65 lukem if (name == NULL) 1049 1.65 lukem return (NULL); 1050 1.65 lukem for (c = optiontab; (p = c->name) != NULL; c++) { 1051 1.65 lukem if (strcasecmp(p, name) == 0) 1052 1.65 lukem return (c); 1053 1.65 lukem } 1054 1.65 lukem return (NULL); 1055 1.65 lukem } 1056 1.65 lukem 1057 1.65 lukem char * 1058 1.70 lukem getoptionvalue(const char *name) 1059 1.65 lukem { 1060 1.65 lukem struct option *c; 1061 1.65 lukem 1062 1.65 lukem if (name == NULL) 1063 1.104 lukem errx(1, "getoptionvalue: invoked with NULL name"); 1064 1.66 lukem c = getoption(name); 1065 1.66 lukem if (c != NULL) 1066 1.66 lukem return (c->value); 1067 1.104 lukem errx(1, "getoptionvalue: invoked with unknown option `%s'", name); 1068 1.72 lukem /* NOTREACHED */ 1069 1.65 lukem } 1070 1.65 lukem 1071 1.65 lukem static void 1072 1.115 lukem setupoption(const char *name, const char *value, const char *defaultvalue) 1073 1.65 lukem { 1074 1.115 lukem set_option(name, value ? value : defaultvalue, 0); 1075 1.12 lukem } 1076 1.12 lukem 1077 1.127 lukem static void 1078 1.127 lukem synopsis(FILE * stream) 1079 1.14 lukem { 1080 1.127 lukem const char * progname = getprogname(); 1081 1.77 cgd 1082 1.127 lukem fprintf(stream, 1083 1.134 lukem "usage: %s [-46AadefginpRtVv] [-b BUFSIZE] [-H HEADER] [-N NETRC] [-o OUTPUT]\n" 1084 1.134 lukem " [-P PORT] [-q QUITTIME] [-r RETRY] [-s SRCADDR] [-T DIR,MAX[,INC]]\n" 1085 1.133 christos " [-x XFERSIZE]\n" 1086 1.127 lukem " [[USER@]HOST [PORT]]\n" 1087 1.127 lukem " [[USER@]HOST:[PATH][/]]\n" 1088 1.127 lukem " [file:///PATH]\n" 1089 1.127 lukem " [ftp://[USER[:PASSWORD]@]HOST[:PORT]/PATH[/][;type=TYPE]]\n" 1090 1.127 lukem " [http://[USER[:PASSWORD]@]HOST[:PORT]/PATH]\n" 1091 1.121 christos #ifdef WITH_SSL 1092 1.127 lukem " [https://[USER[:PASSWORD]@]HOST[:PORT]/PATH]\n" 1093 1.121 christos #endif 1094 1.127 lukem " ...\n" 1095 1.127 lukem " %s -u URL FILE ...\n" 1096 1.127 lukem " %s -?\n", 1097 1.127 lukem progname, progname, progname); 1098 1.127 lukem } 1099 1.127 lukem 1100 1.127 lukem static int 1101 1.127 lukem usage_help(void) 1102 1.127 lukem { 1103 1.127 lukem synopsis(stdout); 1104 1.127 lukem #ifndef NO_USAGE 1105 1.127 lukem printf( 1106 1.127 lukem " -4 Only use IPv4 addresses\n" 1107 1.127 lukem " -6 Only use IPv6 addresses\n" 1108 1.127 lukem " -A Force active mode\n" 1109 1.127 lukem " -a Use anonymous login\n" 1110 1.134 lukem " -b BUFSIZE Use BUFSIZE bytes for fetch buffer\n" 1111 1.127 lukem " -d Enable debugging\n" 1112 1.127 lukem " -e Disable command-line editing\n" 1113 1.127 lukem " -f Force cache reload for FTP or HTTP proxy transfers\n" 1114 1.127 lukem " -g Disable file name globbing\n" 1115 1.134 lukem " -H HEADER Add custom HTTP header HEADER for HTTP transfers;\n" 1116 1.134 lukem " may be repeated for additional headers\n" 1117 1.127 lukem " -i Disable interactive prompt during multiple file transfers\n" 1118 1.127 lukem " -N NETRC Use NETRC instead of ~/.netrc\n" 1119 1.127 lukem " -n Disable auto-login\n" 1120 1.127 lukem " -o OUTPUT Save auto-fetched files to OUTPUT\n" 1121 1.127 lukem " -P PORT Use port PORT\n" 1122 1.127 lukem " -p Force passive mode\n" 1123 1.127 lukem " -q QUITTIME Quit if connection stalls for QUITTIME seconds\n" 1124 1.127 lukem " -R Restart non-proxy auto-fetch\n" 1125 1.127 lukem " -r RETRY Retry failed connection attempts after RETRY seconds\n" 1126 1.134 lukem " -s SRCADDR Use IP source address SRCADDR\n" 1127 1.127 lukem " -T DIR,MAX[,INC]\n" 1128 1.134 lukem " Set maximum transfer rate for direction DIR (all, get, or put)\n" 1129 1.134 lukem " to MAX bytes/s, with optional increment INC bytes/s\n" 1130 1.135 lukem " -t Enable packet tracing\n" 1131 1.127 lukem " -u URL URL to upload file arguments to\n" 1132 1.127 lukem " -V Disable verbose and progress\n" 1133 1.127 lukem " -v Enable verbose and progress\n" 1134 1.134 lukem " -x XFERSIZE Set socket send and receive size to XFERSIZE bytes\n" 1135 1.127 lukem " -? Display this help and exit\n" 1136 1.127 lukem ); 1137 1.127 lukem #endif 1138 1.127 lukem return EXIT_SUCCESS; 1139 1.127 lukem } 1140 1.127 lukem 1141 1.127 lukem static int 1142 1.127 lukem usage(void) 1143 1.127 lukem { 1144 1.127 lukem synopsis(stderr); 1145 1.127 lukem return EXIT_FAILURE; 1146 1.1 cgd } 1147