1 1.32 he /* $NetBSD: main.c,v 1.32 2012/07/16 09:20:26 he Exp $ */ 2 1.5 jtc 3 1.1 cgd /* 4 1.5 jtc * Copyright (c) 1983, 1993 5 1.5 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.17 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.8 mrg #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.26 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 35 1.26 lukem The Regents of the University of California. All rights reserved."); 36 1.5 jtc #if 0 37 1.5 jtc static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; 38 1.8 mrg #else 39 1.32 he __RCSID("$NetBSD: main.c,v 1.32 2012/07/16 09:20:26 he Exp $"); 40 1.5 jtc #endif 41 1.1 cgd #endif /* not lint */ 42 1.1 cgd 43 1.1 cgd /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 44 1.1 cgd 45 1.1 cgd /* 46 1.1 cgd * TFTP User Program -- Command Interface. 47 1.1 cgd */ 48 1.1 cgd #include <sys/types.h> 49 1.29 christos #include <sys/param.h> 50 1.1 cgd #include <sys/socket.h> 51 1.1 cgd 52 1.1 cgd #include <netinet/in.h> 53 1.1 cgd 54 1.5 jtc #include <arpa/inet.h> 55 1.15 briggs #include <arpa/tftp.h> 56 1.5 jtc 57 1.5 jtc #include <ctype.h> 58 1.10 christos #include <fcntl.h> 59 1.9 lukem #include <err.h> 60 1.5 jtc #include <errno.h> 61 1.5 jtc #include <netdb.h> 62 1.5 jtc #include <setjmp.h> 63 1.1 cgd #include <signal.h> 64 1.1 cgd #include <stdio.h> 65 1.5 jtc #include <stdlib.h> 66 1.5 jtc #include <string.h> 67 1.5 jtc #include <unistd.h> 68 1.5 jtc 69 1.5 jtc #include "extern.h" 70 1.1 cgd 71 1.1 cgd #define TIMEOUT 5 /* secs between rexmt's */ 72 1.4 cgd #define LBUFLEN 200 /* size of input buffer */ 73 1.1 cgd 74 1.11 itojun struct sockaddr_storage peeraddr; 75 1.1 cgd int f; 76 1.24 jmcneill int mf; 77 1.1 cgd int trace; 78 1.1 cgd int verbose; 79 1.15 briggs int tsize=0; 80 1.15 briggs int tout=0; 81 1.29 christos size_t def_blksize = SEGSIZE; 82 1.29 christos size_t blksize = SEGSIZE; 83 1.24 jmcneill in_addr_t mcaddr = INADDR_NONE; 84 1.24 jmcneill uint16_t mcport; 85 1.29 christos u_int def_rexmtval = TIMEOUT; 86 1.29 christos u_int rexmtval = TIMEOUT; 87 1.24 jmcneill ushort mcmasterslave; 88 1.29 christos int maxtimeout = 5 * TIMEOUT; 89 1.29 christos 90 1.32 he jmp_buf toplevel; 91 1.32 he 92 1.29 christos static int connected; 93 1.29 christos static char mode[32]; 94 1.29 christos static char line[LBUFLEN]; 95 1.29 christos static int margc; 96 1.29 christos static char *margv[20]; 97 1.29 christos static const char *prompt = "tftp"; 98 1.29 christos static char hostname[MAXHOSTNAMELEN]; 99 1.29 christos 100 1.29 christos static void get(int, char **); 101 1.29 christos static void help(int, char **); 102 1.29 christos static void modecmd(int, char **); 103 1.29 christos static void put(int, char **); 104 1.29 christos static __dead void quit(int, char **); 105 1.29 christos static void setascii(int, char **); 106 1.29 christos static void setbinary(int, char **); 107 1.29 christos static void setpeer0(const char *, const char *); 108 1.29 christos static void setpeer(int, char **); 109 1.29 christos static void setrexmt(int, char **); 110 1.29 christos static void settimeout(int, char **); 111 1.29 christos static void settrace(int, char **); 112 1.29 christos static void setverbose(int, char **); 113 1.29 christos static void setblksize(int, char **); 114 1.29 christos static void settsize(int, char **); 115 1.29 christos static void settimeoutopt(int, char **); 116 1.29 christos static void status(int, char **); 117 1.29 christos static char *tail(char *); 118 1.29 christos static __dead void intr(int); 119 1.29 christos static const struct cmd *getcmd(const char *); 120 1.29 christos 121 1.29 christos static __dead void command(void); 122 1.29 christos 123 1.29 christos static void getUsage(char *); 124 1.29 christos static void makeargv(void); 125 1.29 christos static void putUsage(const char *); 126 1.29 christos static void settftpmode(const char *); 127 1.1 cgd 128 1.29 christos #define HELPINDENT sizeof("connect") 129 1.1 cgd 130 1.1 cgd struct cmd { 131 1.20 ross const char *name; 132 1.20 ross const char *help; 133 1.29 christos void (*handler)(int, char **); 134 1.1 cgd }; 135 1.1 cgd 136 1.29 christos static const char vhelp[] = "toggle verbose mode"; 137 1.29 christos static const char thelp[] = "toggle packet tracing"; 138 1.29 christos static const char tshelp[] = "toggle extended tsize option"; 139 1.29 christos static const char tohelp[] = "toggle extended timeout option"; 140 1.29 christos static const char blhelp[] = "set an alternative blocksize (def. 512)"; 141 1.29 christos static const char chelp[] = "connect to remote tftp"; 142 1.29 christos static const char qhelp[] = "exit tftp"; 143 1.29 christos static const char hhelp[] = "print help information"; 144 1.29 christos static const char shelp[] = "send file"; 145 1.29 christos static const char rhelp[] = "receive file"; 146 1.29 christos static const char mhelp[] = "set file transfer mode"; 147 1.29 christos static const char sthelp[] = "show current status"; 148 1.29 christos static const char xhelp[] = "set per-packet retransmission timeout"; 149 1.29 christos static const char ihelp[] = "set total retransmission timeout"; 150 1.29 christos static const char ashelp[] = "set mode to netascii"; 151 1.29 christos static const char bnhelp[] = "set mode to octet"; 152 1.1 cgd 153 1.29 christos static const struct cmd cmdtab[] = { 154 1.1 cgd { "connect", chelp, setpeer }, 155 1.1 cgd { "mode", mhelp, modecmd }, 156 1.1 cgd { "put", shelp, put }, 157 1.1 cgd { "get", rhelp, get }, 158 1.1 cgd { "quit", qhelp, quit }, 159 1.1 cgd { "verbose", vhelp, setverbose }, 160 1.15 briggs { "blksize", blhelp, setblksize }, 161 1.15 briggs { "tsize", tshelp, settsize }, 162 1.1 cgd { "trace", thelp, settrace }, 163 1.1 cgd { "status", sthelp, status }, 164 1.1 cgd { "binary", bnhelp, setbinary }, 165 1.1 cgd { "ascii", ashelp, setascii }, 166 1.1 cgd { "rexmt", xhelp, setrexmt }, 167 1.1 cgd { "timeout", ihelp, settimeout }, 168 1.15 briggs { "tout", tohelp, settimeoutopt }, 169 1.1 cgd { "?", hhelp, help }, 170 1.25 christos { .name = NULL } 171 1.1 cgd }; 172 1.1 cgd 173 1.29 christos static struct modes { 174 1.29 christos const char *m_name; 175 1.29 christos const char *m_mode; 176 1.29 christos } modes[] = { 177 1.29 christos { "ascii", "netascii" }, 178 1.29 christos { "netascii", "netascii" }, 179 1.29 christos { "binary", "octet" }, 180 1.29 christos { "image", "octet" }, 181 1.29 christos { "octet", "octet" }, 182 1.29 christos /* { "mail", "mail" }, */ 183 1.29 christos { 0, 0 } 184 1.29 christos }; 185 1.29 christos 186 1.5 jtc int 187 1.29 christos main(int argc, char *argv[]) 188 1.1 cgd { 189 1.15 briggs int c; 190 1.15 briggs 191 1.24 jmcneill f = mf = -1; 192 1.22 christos (void)strlcpy(mode, "netascii", sizeof(mode)); 193 1.22 christos (void)signal(SIGINT, intr); 194 1.15 briggs 195 1.15 briggs setprogname(argv[0]); 196 1.15 briggs while ((c = getopt(argc, argv, "e")) != -1) { 197 1.15 briggs switch (c) { 198 1.15 briggs case 'e': 199 1.15 briggs blksize = MAXSEGSIZE; 200 1.22 christos (void)strlcpy(mode, "octet", sizeof(mode)); 201 1.15 briggs tsize = 1; 202 1.15 briggs tout = 1; 203 1.15 briggs break; 204 1.15 briggs default: 205 1.29 christos (void)fprintf(stderr, 206 1.29 christos "Usage: %s [-e] host-name [port]\n", getprogname()); 207 1.15 briggs exit(1); 208 1.15 briggs } 209 1.15 briggs } 210 1.15 briggs argc -= optind; 211 1.15 briggs argv += optind; 212 1.15 briggs 213 1.15 briggs if (argc >= 1) { 214 1.1 cgd if (setjmp(toplevel) != 0) 215 1.1 cgd exit(0); 216 1.19 itojun argc++; 217 1.19 itojun argv--; 218 1.1 cgd setpeer(argc, argv); 219 1.1 cgd } 220 1.5 jtc if (setjmp(toplevel) != 0) 221 1.5 jtc (void)putchar('\n'); 222 1.5 jtc command(); 223 1.29 christos return 0; 224 1.1 cgd } 225 1.1 cgd 226 1.29 christos static void 227 1.29 christos getmore(const char *cmd, const char *prm) 228 1.29 christos { 229 1.29 christos (void)strlcpy(line, cmd, sizeof(line)); 230 1.29 christos (void)printf("%s", prm); 231 1.29 christos (void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin); 232 1.29 christos makeargv(); 233 1.29 christos } 234 1.1 cgd 235 1.29 christos static void 236 1.29 christos setpeer0(const char *host, const char *port) 237 1.11 itojun { 238 1.11 itojun struct addrinfo hints, *res0, *res; 239 1.15 briggs int error, soopt; 240 1.11 itojun struct sockaddr_storage ss; 241 1.20 ross const char *cause = "unknown"; 242 1.11 itojun 243 1.11 itojun if (connected) { 244 1.21 christos (void)close(f); 245 1.11 itojun f = -1; 246 1.11 itojun } 247 1.12 itojun connected = 0; 248 1.11 itojun 249 1.22 christos (void)memset(&hints, 0, sizeof(hints)); 250 1.11 itojun hints.ai_family = PF_UNSPEC; 251 1.11 itojun hints.ai_socktype = SOCK_DGRAM; 252 1.11 itojun hints.ai_protocol = IPPROTO_UDP; 253 1.11 itojun hints.ai_flags = AI_CANONNAME; 254 1.11 itojun if (!port) 255 1.11 itojun port = "tftp"; 256 1.11 itojun error = getaddrinfo(host, port, &hints, &res0); 257 1.11 itojun if (error) { 258 1.11 itojun warnx("%s", gai_strerror(error)); 259 1.11 itojun return; 260 1.11 itojun } 261 1.11 itojun 262 1.11 itojun for (res = res0; res; res = res->ai_next) { 263 1.13 itojun if (res->ai_addrlen > sizeof(peeraddr)) 264 1.13 itojun continue; 265 1.11 itojun f = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 266 1.29 christos if (f == -1) { 267 1.11 itojun cause = "socket"; 268 1.11 itojun continue; 269 1.11 itojun } 270 1.11 itojun 271 1.22 christos (void)memset(&ss, 0, sizeof(ss)); 272 1.11 itojun ss.ss_family = res->ai_family; 273 1.11 itojun ss.ss_len = res->ai_addrlen; 274 1.21 christos if (bind(f, (struct sockaddr *)(void *)&ss, 275 1.29 christos (socklen_t)ss.ss_len) == -1) { 276 1.11 itojun cause = "bind"; 277 1.22 christos (void)close(f); 278 1.11 itojun f = -1; 279 1.11 itojun continue; 280 1.11 itojun } 281 1.11 itojun 282 1.11 itojun break; 283 1.11 itojun } 284 1.11 itojun 285 1.15 briggs if (f >= 0) { 286 1.15 briggs soopt = 65536; 287 1.15 briggs if (setsockopt(f, SOL_SOCKET, SO_SNDBUF, &soopt, sizeof(soopt)) 288 1.29 christos == -1) { 289 1.22 christos (void)close(f); 290 1.15 briggs f = -1; 291 1.15 briggs cause = "setsockopt SNDBUF"; 292 1.15 briggs } 293 1.29 christos else if (setsockopt(f, SOL_SOCKET, SO_RCVBUF, &soopt, 294 1.29 christos sizeof(soopt)) == -1) { 295 1.22 christos (void)close(f); 296 1.15 briggs f = -1; 297 1.15 briggs cause = "setsockopt RCVBUF"; 298 1.15 briggs } 299 1.15 briggs } 300 1.15 briggs 301 1.29 christos if (f == -1 || res == NULL) 302 1.11 itojun warn("%s", cause); 303 1.11 itojun else { 304 1.13 itojun /* res->ai_addr <= sizeof(peeraddr) is guaranteed */ 305 1.22 christos (void)memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); 306 1.11 itojun if (res->ai_canonname) { 307 1.22 christos (void)strlcpy(hostname, res->ai_canonname, 308 1.16 itojun sizeof(hostname)); 309 1.11 itojun } else 310 1.22 christos (void)strlcpy(hostname, host, sizeof(hostname)); 311 1.11 itojun connected = 1; 312 1.11 itojun } 313 1.12 itojun 314 1.12 itojun freeaddrinfo(res0); 315 1.11 itojun } 316 1.11 itojun 317 1.29 christos static void 318 1.29 christos setpeer(int argc, char *argv[]) 319 1.1 cgd { 320 1.1 cgd 321 1.18 itojun if (argc < 2) { 322 1.29 christos getmore("Connect ", "(to) "); 323 1.1 cgd argc = margc; 324 1.1 cgd argv = margv; 325 1.1 cgd } 326 1.29 christos if (argc < 2 || argc > 3) { 327 1.29 christos (void)printf("Usage: %s [-e] host-name [port]\n", 328 1.29 christos getprogname()); 329 1.1 cgd return; 330 1.1 cgd } 331 1.18 itojun if (argc == 2) 332 1.18 itojun setpeer0(argv[1], NULL); 333 1.11 itojun else 334 1.18 itojun setpeer0(argv[1], argv[2]); 335 1.1 cgd } 336 1.1 cgd 337 1.29 christos static void 338 1.29 christos modecmd(int argc, char *argv[]) 339 1.1 cgd { 340 1.9 lukem struct modes *p; 341 1.20 ross const char *sep; 342 1.1 cgd 343 1.1 cgd if (argc < 2) { 344 1.22 christos (void)printf("Using %s mode to transfer files.\n", mode); 345 1.1 cgd return; 346 1.1 cgd } 347 1.1 cgd if (argc == 2) { 348 1.1 cgd for (p = modes; p->m_name; p++) 349 1.1 cgd if (strcmp(argv[1], p->m_name) == 0) 350 1.1 cgd break; 351 1.1 cgd if (p->m_name) { 352 1.5 jtc settftpmode(p->m_mode); 353 1.1 cgd return; 354 1.1 cgd } 355 1.22 christos (void)printf("%s: unknown mode\n", argv[1]); 356 1.29 christos /* drop through and print Usage message */ 357 1.1 cgd } 358 1.1 cgd 359 1.29 christos (void)printf("Usage: %s [", argv[0]); 360 1.1 cgd sep = " "; 361 1.1 cgd for (p = modes; p->m_name; p++) { 362 1.22 christos (void)printf("%s%s", sep, p->m_name); 363 1.1 cgd if (*sep == ' ') 364 1.1 cgd sep = " | "; 365 1.1 cgd } 366 1.22 christos (void)printf(" ]\n"); 367 1.1 cgd return; 368 1.1 cgd } 369 1.1 cgd 370 1.29 christos static void 371 1.21 christos /*ARGSUSED*/ 372 1.29 christos setbinary(int argc, char *argv[]) 373 1.5 jtc { 374 1.5 jtc 375 1.5 jtc settftpmode("octet"); 376 1.1 cgd } 377 1.1 cgd 378 1.29 christos static void 379 1.21 christos /*ARGSUSED*/ 380 1.29 christos setascii(int argc, char *argv[]) 381 1.5 jtc { 382 1.5 jtc 383 1.5 jtc settftpmode("netascii"); 384 1.1 cgd } 385 1.1 cgd 386 1.5 jtc static void 387 1.29 christos settftpmode(const char *newmode) 388 1.1 cgd { 389 1.22 christos (void)strlcpy(mode, newmode, sizeof(mode)); 390 1.1 cgd if (verbose) 391 1.22 christos (void)printf("mode set to %s\n", mode); 392 1.1 cgd } 393 1.1 cgd 394 1.1 cgd 395 1.1 cgd /* 396 1.1 cgd * Send file(s). 397 1.1 cgd */ 398 1.29 christos static void 399 1.29 christos put(int argc, char *argv[]) 400 1.1 cgd { 401 1.1 cgd int fd; 402 1.9 lukem int n; 403 1.20 ross char *targ, *p; 404 1.1 cgd 405 1.1 cgd if (argc < 2) { 406 1.29 christos getmore("send ", "(file) "); 407 1.1 cgd argc = margc; 408 1.1 cgd argv = margv; 409 1.1 cgd } 410 1.1 cgd if (argc < 2) { 411 1.29 christos putUsage(argv[0]); 412 1.1 cgd return; 413 1.1 cgd } 414 1.1 cgd targ = argv[argc - 1]; 415 1.11 itojun if (strrchr(argv[argc - 1], ':')) { 416 1.1 cgd char *cp; 417 1.1 cgd 418 1.1 cgd for (n = 1; n < argc - 1; n++) 419 1.9 lukem if (strchr(argv[n], ':')) { 420 1.29 christos putUsage(argv[0]); 421 1.1 cgd return; 422 1.1 cgd } 423 1.1 cgd cp = argv[argc - 1]; 424 1.11 itojun targ = strrchr(cp, ':'); 425 1.1 cgd *targ++ = 0; 426 1.11 itojun if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') { 427 1.11 itojun cp[strlen(cp) - 1] = '\0'; 428 1.11 itojun cp++; 429 1.1 cgd } 430 1.11 itojun setpeer0(cp, NULL); 431 1.1 cgd } 432 1.1 cgd if (!connected) { 433 1.22 christos (void)printf("No target machine specified.\n"); 434 1.1 cgd return; 435 1.1 cgd } 436 1.1 cgd if (argc < 4) { 437 1.20 ross char *cp = argc == 2 ? tail(targ) : argv[1]; 438 1.1 cgd fd = open(cp, O_RDONLY); 439 1.29 christos if (fd == -1) { 440 1.9 lukem warn("%s", cp); 441 1.1 cgd return; 442 1.1 cgd } 443 1.1 cgd if (verbose) 444 1.22 christos (void)printf("putting %s to %s:%s [%s]\n", 445 1.1 cgd cp, hostname, targ, mode); 446 1.1 cgd sendfile(fd, targ, mode); 447 1.1 cgd return; 448 1.1 cgd } 449 1.1 cgd /* this assumes the target is a directory */ 450 1.1 cgd /* on a remote unix system. hmmmm. */ 451 1.20 ross p = strchr(targ, '\0'); 452 1.20 ross *p++ = '/'; 453 1.1 cgd for (n = 1; n < argc - 1; n++) { 454 1.22 christos (void)strcpy(p, tail(argv[n])); 455 1.1 cgd fd = open(argv[n], O_RDONLY); 456 1.29 christos if (fd == -1) { 457 1.9 lukem warn("%s", argv[n]); 458 1.1 cgd continue; 459 1.1 cgd } 460 1.1 cgd if (verbose) 461 1.22 christos (void)printf("putting %s to %s:%s [%s]\n", 462 1.1 cgd argv[n], hostname, targ, mode); 463 1.1 cgd sendfile(fd, targ, mode); 464 1.1 cgd } 465 1.1 cgd } 466 1.1 cgd 467 1.5 jtc static void 468 1.29 christos putUsage(const char *s) 469 1.1 cgd { 470 1.29 christos (void)printf("Usage: %s file ... host:target, or\n", s); 471 1.22 christos (void)printf(" %s file ... target (when already connected)\n", s); 472 1.1 cgd } 473 1.1 cgd 474 1.1 cgd /* 475 1.1 cgd * Receive file(s). 476 1.1 cgd */ 477 1.29 christos static void 478 1.29 christos get(int argc, char *argv[]) 479 1.1 cgd { 480 1.1 cgd int fd; 481 1.9 lukem int n; 482 1.20 ross char *p; 483 1.1 cgd char *src; 484 1.1 cgd 485 1.1 cgd if (argc < 2) { 486 1.29 christos getmore("get ", "(files) "); 487 1.1 cgd argc = margc; 488 1.1 cgd argv = margv; 489 1.1 cgd } 490 1.1 cgd if (argc < 2) { 491 1.29 christos getUsage(argv[0]); 492 1.1 cgd return; 493 1.1 cgd } 494 1.1 cgd if (!connected) { 495 1.1 cgd for (n = 1; n < argc ; n++) 496 1.11 itojun if (strrchr(argv[n], ':') == 0) { 497 1.29 christos getUsage(argv[0]); 498 1.1 cgd return; 499 1.1 cgd } 500 1.1 cgd } 501 1.1 cgd for (n = 1; n < argc ; n++) { 502 1.11 itojun src = strrchr(argv[n], ':'); 503 1.1 cgd if (src == NULL) 504 1.1 cgd src = argv[n]; 505 1.1 cgd else { 506 1.11 itojun char *cp; 507 1.1 cgd *src++ = 0; 508 1.11 itojun cp = argv[n]; 509 1.11 itojun if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') { 510 1.11 itojun cp[strlen(cp) - 1] = '\0'; 511 1.11 itojun cp++; 512 1.11 itojun } 513 1.11 itojun setpeer0(cp, NULL); 514 1.11 itojun if (!connected) 515 1.1 cgd continue; 516 1.1 cgd } 517 1.1 cgd if (argc < 4) { 518 1.20 ross char *cp = argc == 3 ? argv[2] : tail(src); 519 1.1 cgd fd = creat(cp, 0644); 520 1.29 christos if (fd == -1) { 521 1.9 lukem warn("%s", cp); 522 1.1 cgd return; 523 1.1 cgd } 524 1.1 cgd if (verbose) 525 1.22 christos (void)printf("getting from %s:%s to %s [%s]\n", 526 1.1 cgd hostname, src, cp, mode); 527 1.1 cgd recvfile(fd, src, mode); 528 1.1 cgd break; 529 1.1 cgd } 530 1.20 ross p = tail(src); /* new .. jdg */ 531 1.20 ross fd = creat(p, 0644); 532 1.29 christos if (fd == -1) { 533 1.20 ross warn("%s", p); 534 1.1 cgd continue; 535 1.1 cgd } 536 1.1 cgd if (verbose) 537 1.22 christos (void)printf("getting from %s:%s to %s [%s]\n", 538 1.20 ross hostname, src, p, mode); 539 1.1 cgd recvfile(fd, src, mode); 540 1.1 cgd } 541 1.1 cgd } 542 1.1 cgd 543 1.5 jtc static void 544 1.31 matt getUsage(char *s) 545 1.1 cgd { 546 1.29 christos (void)printf("Usage: %s host:file host:file ... file, or\n", s); 547 1.22 christos (void)printf(" %s file file ... file if connected\n", s); 548 1.1 cgd } 549 1.1 cgd 550 1.15 briggs void 551 1.31 matt setblksize(int argc, char *argv[]) 552 1.15 briggs { 553 1.15 briggs int t; 554 1.15 briggs 555 1.15 briggs if (argc < 2) { 556 1.29 christos getmore("blksize ", "(blksize) "); 557 1.15 briggs argc = margc; 558 1.15 briggs argv = margv; 559 1.15 briggs } 560 1.15 briggs if (argc != 2) { 561 1.29 christos (void)printf("Usage: %s value\n", argv[0]); 562 1.15 briggs return; 563 1.15 briggs } 564 1.15 briggs t = atoi(argv[1]); 565 1.15 briggs if (t < 8 || t > 65464) 566 1.22 christos (void)printf("%s: bad value\n", argv[1]); 567 1.15 briggs else 568 1.15 briggs blksize = t; 569 1.15 briggs } 570 1.15 briggs 571 1.29 christos static void 572 1.29 christos setrexmt(int argc, char *argv[]) 573 1.1 cgd { 574 1.1 cgd int t; 575 1.1 cgd 576 1.1 cgd if (argc < 2) { 577 1.29 christos getmore("Rexmt-timeout ", "(value) "); 578 1.1 cgd argc = margc; 579 1.1 cgd argv = margv; 580 1.1 cgd } 581 1.1 cgd if (argc != 2) { 582 1.29 christos (void)printf("Usage: %s value\n", argv[0]); 583 1.1 cgd return; 584 1.1 cgd } 585 1.1 cgd t = atoi(argv[1]); 586 1.1 cgd if (t < 0) 587 1.22 christos (void)printf("%s: bad value\n", argv[1]); 588 1.1 cgd else 589 1.1 cgd rexmtval = t; 590 1.1 cgd } 591 1.1 cgd 592 1.29 christos static void 593 1.29 christos settimeout(int argc, char *argv[]) 594 1.1 cgd { 595 1.1 cgd int t; 596 1.1 cgd 597 1.1 cgd if (argc < 2) { 598 1.29 christos getmore("Maximum-timeout ", "(value) "); 599 1.1 cgd argc = margc; 600 1.1 cgd argv = margv; 601 1.1 cgd } 602 1.1 cgd if (argc != 2) { 603 1.29 christos (void)printf("Usage: %s value\n", argv[0]); 604 1.1 cgd return; 605 1.1 cgd } 606 1.1 cgd t = atoi(argv[1]); 607 1.1 cgd if (t < 0) 608 1.22 christos (void)printf("%s: bad value\n", argv[1]); 609 1.1 cgd else 610 1.1 cgd maxtimeout = t; 611 1.1 cgd } 612 1.1 cgd 613 1.29 christos static void 614 1.21 christos /*ARGSUSED*/ 615 1.29 christos status(int argc, char *argv[]) 616 1.1 cgd { 617 1.1 cgd if (connected) 618 1.22 christos (void)printf("Connected to %s.\n", hostname); 619 1.1 cgd else 620 1.22 christos (void)printf("Not connected.\n"); 621 1.22 christos (void)printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 622 1.1 cgd verbose ? "on" : "off", trace ? "on" : "off"); 623 1.22 christos (void)printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 624 1.1 cgd rexmtval, maxtimeout); 625 1.1 cgd } 626 1.1 cgd 627 1.29 christos static void 628 1.21 christos /*ARGSUSED*/ 629 1.29 christos intr(int dummy) 630 1.1 cgd { 631 1.5 jtc 632 1.22 christos (void)signal(SIGALRM, SIG_IGN); 633 1.22 christos (void)alarm(0); 634 1.1 cgd longjmp(toplevel, -1); 635 1.1 cgd } 636 1.1 cgd 637 1.29 christos static char * 638 1.29 christos tail(char *filename) 639 1.1 cgd { 640 1.9 lukem char *s; 641 1.1 cgd 642 1.1 cgd while (*filename) { 643 1.9 lukem s = strrchr(filename, '/'); 644 1.1 cgd if (s == NULL) 645 1.1 cgd break; 646 1.1 cgd if (s[1]) 647 1.29 christos return s + 1; 648 1.1 cgd *s = '\0'; 649 1.1 cgd } 650 1.29 christos return filename; 651 1.1 cgd } 652 1.1 cgd 653 1.1 cgd /* 654 1.1 cgd * Command parser. 655 1.1 cgd */ 656 1.5 jtc static __dead void 657 1.29 christos command(void) 658 1.1 cgd { 659 1.20 ross const struct cmd *c; 660 1.1 cgd 661 1.1 cgd for (;;) { 662 1.22 christos (void)printf("%s> ", prompt); 663 1.30 christos if (fgets(line, LBUFLEN, stdin) == NULL) { 664 1.1 cgd if (feof(stdin)) { 665 1.5 jtc exit(0); 666 1.1 cgd } else { 667 1.1 cgd continue; 668 1.1 cgd } 669 1.1 cgd } 670 1.29 christos if (line[0] == '\0' || line[0] == '\n') 671 1.1 cgd continue; 672 1.1 cgd makeargv(); 673 1.5 jtc if (margc == 0) 674 1.5 jtc continue; 675 1.1 cgd c = getcmd(margv[0]); 676 1.1 cgd if (c == (struct cmd *)-1) { 677 1.22 christos (void)printf("?Ambiguous command\n"); 678 1.1 cgd continue; 679 1.1 cgd } 680 1.1 cgd if (c == 0) { 681 1.22 christos (void)printf("?Invalid command\n"); 682 1.1 cgd continue; 683 1.1 cgd } 684 1.1 cgd (*c->handler)(margc, margv); 685 1.1 cgd } 686 1.1 cgd } 687 1.1 cgd 688 1.29 christos static const struct cmd * 689 1.29 christos getcmd(const char *name) 690 1.1 cgd { 691 1.20 ross const char *p, *q; 692 1.20 ross const struct cmd *c, *found; 693 1.9 lukem int nmatches, longest; 694 1.1 cgd 695 1.1 cgd longest = 0; 696 1.1 cgd nmatches = 0; 697 1.1 cgd found = 0; 698 1.5 jtc for (c = cmdtab; (p = c->name) != NULL; c++) { 699 1.1 cgd for (q = name; *q == *p++; q++) 700 1.1 cgd if (*q == 0) /* exact match? */ 701 1.29 christos return c; 702 1.1 cgd if (!*q) { /* the name was a prefix */ 703 1.1 cgd if (q - name > longest) { 704 1.1 cgd longest = q - name; 705 1.1 cgd nmatches = 1; 706 1.1 cgd found = c; 707 1.1 cgd } else if (q - name == longest) 708 1.1 cgd nmatches++; 709 1.1 cgd } 710 1.1 cgd } 711 1.1 cgd if (nmatches > 1) 712 1.29 christos return (struct cmd *)-1; 713 1.29 christos return found; 714 1.1 cgd } 715 1.1 cgd 716 1.1 cgd /* 717 1.1 cgd * Slice a string up into argc/argv. 718 1.1 cgd */ 719 1.5 jtc static void 720 1.29 christos makeargv(void) 721 1.1 cgd { 722 1.9 lukem char *cp; 723 1.9 lukem char **argp = margv; 724 1.1 cgd 725 1.1 cgd margc = 0; 726 1.1 cgd for (cp = line; *cp;) { 727 1.10 christos while (isspace((unsigned char)*cp)) 728 1.1 cgd cp++; 729 1.1 cgd if (*cp == '\0') 730 1.1 cgd break; 731 1.1 cgd *argp++ = cp; 732 1.1 cgd margc += 1; 733 1.10 christos while (*cp != '\0' && !isspace((unsigned char)*cp)) 734 1.1 cgd cp++; 735 1.1 cgd if (*cp == '\0') 736 1.1 cgd break; 737 1.1 cgd *cp++ = '\0'; 738 1.1 cgd } 739 1.29 christos *argp++ = NULL; 740 1.1 cgd } 741 1.1 cgd 742 1.29 christos static void 743 1.21 christos /*ARGSUSED*/ 744 1.29 christos quit(int argc, char *argv[]) 745 1.1 cgd { 746 1.5 jtc 747 1.1 cgd exit(0); 748 1.1 cgd } 749 1.1 cgd 750 1.1 cgd /* 751 1.1 cgd * Help command. 752 1.1 cgd */ 753 1.29 christos static void 754 1.29 christos help(int argc, char *argv[]) 755 1.1 cgd { 756 1.20 ross const struct cmd *c; 757 1.1 cgd 758 1.1 cgd if (argc == 1) { 759 1.22 christos (void)printf("Commands may be abbreviated. Commands are:\n\n"); 760 1.1 cgd for (c = cmdtab; c->name; c++) 761 1.29 christos (void)printf("%-*s\t%s\n", (int)HELPINDENT, c->name, 762 1.29 christos c->help); 763 1.1 cgd return; 764 1.1 cgd } 765 1.1 cgd while (--argc > 0) { 766 1.9 lukem char *arg; 767 1.1 cgd arg = *++argv; 768 1.1 cgd c = getcmd(arg); 769 1.1 cgd if (c == (struct cmd *)-1) 770 1.22 christos (void)printf("?Ambiguous help command %s\n", arg); 771 1.29 christos else if (c == NULL) 772 1.22 christos (void)printf("?Invalid help command %s\n", arg); 773 1.1 cgd else 774 1.22 christos (void)printf("%s\n", c->help); 775 1.1 cgd } 776 1.1 cgd } 777 1.1 cgd 778 1.29 christos static void 779 1.21 christos /*ARGSUSED*/ 780 1.29 christos settrace(int argc, char **argv) 781 1.1 cgd { 782 1.1 cgd trace = !trace; 783 1.22 christos (void)printf("Packet tracing %s.\n", trace ? "on" : "off"); 784 1.1 cgd } 785 1.1 cgd 786 1.29 christos static void 787 1.21 christos /*ARGSUSED*/ 788 1.29 christos setverbose(int argc, char **argv) 789 1.1 cgd { 790 1.1 cgd verbose = !verbose; 791 1.22 christos (void)printf("Verbose mode %s.\n", verbose ? "on" : "off"); 792 1.15 briggs } 793 1.15 briggs 794 1.29 christos static void 795 1.21 christos /*ARGSUSED*/ 796 1.29 christos settsize(int argc, char **argv) 797 1.15 briggs { 798 1.15 briggs tsize = !tsize; 799 1.22 christos (void)printf("Tsize mode %s.\n", tsize ? "on" : "off"); 800 1.15 briggs } 801 1.15 briggs 802 1.29 christos static void 803 1.21 christos /*ARGSUSED*/ 804 1.29 christos settimeoutopt(int argc, char **argv) 805 1.15 briggs { 806 1.15 briggs tout = !tout; 807 1.22 christos (void)printf("Timeout option %s.\n", tout ? "on" : "off"); 808 1.1 cgd } 809