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