122403Sdist /* 233821Sbostic * Copyright (c) 1983 Regents of the University of California. 333821Sbostic * All rights reserved. 433821Sbostic * 533821Sbostic * Redistribution and use in source and binary forms are permitted 6*34903Sbostic * provided that the above copyright notice and this paragraph are 7*34903Sbostic * duplicated in all such forms and that any documentation, 8*34903Sbostic * advertising materials, and other materials related to such 9*34903Sbostic * distribution and use acknowledge that the software was developed 10*34903Sbostic * by the University of California, Berkeley. The name of the 11*34903Sbostic * University may not be used to endorse or promote products derived 12*34903Sbostic * from this software without specific prior written permission. 13*34903Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34903Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34903Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622403Sdist */ 1722403Sdist 1814553Ssam #ifndef lint 1922403Sdist char copyright[] = 2022403Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 2122403Sdist All rights reserved.\n"; 2233821Sbostic #endif /* not lint */ 237769Ssam 2422403Sdist #ifndef lint 25*34903Sbostic static char sccsid[] = "@(#)main.c 5.7 (Berkeley) 06/29/88"; 2633821Sbostic #endif /* not lint */ 2722403Sdist 2826095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 2926095Sminshall 307769Ssam /* 317769Ssam * TFTP User Program -- Command Interface. 327769Ssam */ 337769Ssam #include <sys/types.h> 347769Ssam #include <sys/socket.h> 3513017Ssam #include <sys/file.h> 369219Ssam 379219Ssam #include <netinet/in.h> 389219Ssam 397769Ssam #include <signal.h> 407769Ssam #include <stdio.h> 417769Ssam #include <errno.h> 427769Ssam #include <setjmp.h> 437769Ssam #include <ctype.h> 448384Ssam #include <netdb.h> 457769Ssam 4613017Ssam #define TIMEOUT 5 /* secs between rexmt's */ 4713017Ssam 4826095Sminshall struct sockaddr_in sin; 497769Ssam int f; 5026095Sminshall short port; 517769Ssam int trace; 5226095Sminshall int verbose; 537769Ssam int connected; 547769Ssam char mode[32]; 557769Ssam char line[200]; 567769Ssam int margc; 577769Ssam char *margv[20]; 587769Ssam char *prompt = "tftp"; 597769Ssam jmp_buf toplevel; 607769Ssam int intr(); 618384Ssam struct servent *sp; 627769Ssam 6326095Sminshall int quit(), help(), setverbose(), settrace(), status(); 6426095Sminshall int get(), put(), setpeer(), modecmd(), setrexmt(), settimeout(); 6526095Sminshall int setbinary(), setascii(); 667769Ssam 677769Ssam #define HELPINDENT (sizeof("connect")) 687769Ssam 697769Ssam struct cmd { 707769Ssam char *name; 717769Ssam char *help; 727769Ssam int (*handler)(); 737769Ssam }; 747769Ssam 7526095Sminshall char vhelp[] = "toggle verbose mode"; 767769Ssam char thelp[] = "toggle packet tracing"; 777769Ssam char chelp[] = "connect to remote tftp"; 787769Ssam char qhelp[] = "exit tftp"; 797769Ssam char hhelp[] = "print help information"; 807769Ssam char shelp[] = "send file"; 817769Ssam char rhelp[] = "receive file"; 827769Ssam char mhelp[] = "set file transfer mode"; 837769Ssam char sthelp[] = "show current status"; 8413017Ssam char xhelp[] = "set per-packet retransmission timeout"; 8513017Ssam char ihelp[] = "set total retransmission timeout"; 8626095Sminshall char ashelp[] = "set mode to netascii"; 8726095Sminshall char bnhelp[] = "set mode to octet"; 887769Ssam 897769Ssam struct cmd cmdtab[] = { 907769Ssam { "connect", chelp, setpeer }, 9126095Sminshall { "mode", mhelp, modecmd }, 927769Ssam { "put", shelp, put }, 937769Ssam { "get", rhelp, get }, 947769Ssam { "quit", qhelp, quit }, 9526095Sminshall { "verbose", vhelp, setverbose }, 967769Ssam { "trace", thelp, settrace }, 977769Ssam { "status", sthelp, status }, 9826095Sminshall { "binary", bnhelp, setbinary }, 9926095Sminshall { "ascii", ashelp, setascii }, 10013017Ssam { "rexmt", xhelp, setrexmt }, 10113017Ssam { "timeout", ihelp, settimeout }, 1027769Ssam { "?", hhelp, help }, 1037769Ssam 0 1047769Ssam }; 1057769Ssam 1067769Ssam struct cmd *getcmd(); 1077769Ssam char *tail(); 1087769Ssam char *index(); 1097769Ssam char *rindex(); 1107769Ssam 1117769Ssam main(argc, argv) 1127769Ssam char *argv[]; 1137769Ssam { 11426095Sminshall struct sockaddr_in sin; 11513017Ssam int top; 11613017Ssam 1178384Ssam sp = getservbyname("tftp", "udp"); 1188384Ssam if (sp == 0) { 1198384Ssam fprintf(stderr, "tftp: udp/tftp: unknown service\n"); 1208384Ssam exit(1); 1218384Ssam } 12226110Sminshall f = socket(AF_INET, SOCK_DGRAM, 0); 1237769Ssam if (f < 0) { 12413017Ssam perror("tftp: socket"); 1257769Ssam exit(3); 1267769Ssam } 12726095Sminshall bzero((char *)&sin, sizeof (sin)); 12826095Sminshall sin.sin_family = AF_INET; 12913017Ssam if (bind(f, &sin, sizeof (sin)) < 0) { 13013017Ssam perror("tftp: bind"); 13113017Ssam exit(1); 13213017Ssam } 13326095Sminshall strcpy(mode, "netascii"); 13413017Ssam signal(SIGINT, intr); 1357769Ssam if (argc > 1) { 1367769Ssam if (setjmp(toplevel) != 0) 1377769Ssam exit(0); 1387769Ssam setpeer(argc, argv); 1397769Ssam } 14013017Ssam top = setjmp(toplevel) == 0; 1417769Ssam for (;;) 14213017Ssam command(top); 1437769Ssam } 1447769Ssam 14526095Sminshall char hostname[100]; 1467769Ssam 1477769Ssam setpeer(argc, argv) 1487769Ssam int argc; 1497769Ssam char *argv[]; 1507769Ssam { 1518384Ssam struct hostent *host; 1527769Ssam 1537769Ssam if (argc < 2) { 1547769Ssam strcpy(line, "Connect "); 1557769Ssam printf("(to) "); 1567769Ssam gets(&line[strlen(line)]); 1577769Ssam makeargv(); 1587769Ssam argc = margc; 1597769Ssam argv = margv; 1607769Ssam } 1617769Ssam if (argc > 3) { 1627769Ssam printf("usage: %s host-name [port]\n", argv[0]); 1637769Ssam return; 1647769Ssam } 1658384Ssam host = gethostbyname(argv[1]); 1668384Ssam if (host) { 1679219Ssam sin.sin_family = host->h_addrtype; 1688384Ssam bcopy(host->h_addr, &sin.sin_addr, host->h_length); 16926095Sminshall strcpy(hostname, host->h_name); 1708384Ssam } else { 1719219Ssam sin.sin_family = AF_INET; 1728384Ssam sin.sin_addr.s_addr = inet_addr(argv[1]); 1738384Ssam if (sin.sin_addr.s_addr == -1) { 1748384Ssam connected = 0; 1758384Ssam printf("%s: unknown host\n", argv[1]); 1768384Ssam return; 1778384Ssam } 17826095Sminshall strcpy(hostname, argv[1]); 1797769Ssam } 18026095Sminshall port = sp->s_port; 1817769Ssam if (argc == 3) { 18226095Sminshall port = atoi(argv[2]); 18326095Sminshall if (port < 0) { 1847769Ssam printf("%s: bad port number\n", argv[2]); 1857769Ssam connected = 0; 1867769Ssam return; 1877769Ssam } 18826095Sminshall port = htons(port); 1898384Ssam } 1907769Ssam connected = 1; 1917769Ssam } 1927769Ssam 1937769Ssam struct modes { 1947769Ssam char *m_name; 1957769Ssam char *m_mode; 1967769Ssam } modes[] = { 19726095Sminshall { "ascii", "netascii" }, 19826095Sminshall { "netascii", "netascii" }, 19926095Sminshall { "binary", "octet" }, 20026095Sminshall { "image", "octet" }, 20126103Sminshall { "octet", "octet" }, 20226095Sminshall /* { "mail", "mail" }, */ 2037769Ssam { 0, 0 } 2047769Ssam }; 2057769Ssam 20626095Sminshall modecmd(argc, argv) 2077769Ssam char *argv[]; 2087769Ssam { 2097769Ssam register struct modes *p; 21026095Sminshall char *sep; 2117769Ssam 2127769Ssam if (argc < 2) { 2137769Ssam printf("Using %s mode to transfer files.\n", mode); 2147769Ssam return; 2157769Ssam } 21626095Sminshall if (argc == 2) { 21726095Sminshall for (p = modes; p->m_name; p++) 21826095Sminshall if (strcmp(argv[1], p->m_name) == 0) 21926095Sminshall break; 22026095Sminshall if (p->m_name) { 22126095Sminshall setmode(p->m_mode); 22226095Sminshall return; 22326095Sminshall } 2247769Ssam printf("%s: unknown mode\n", argv[1]); 22526095Sminshall /* drop through and print usage message */ 22626095Sminshall } 22726095Sminshall 22826095Sminshall printf("usage: %s [", argv[0]); 22926095Sminshall sep = " "; 23026095Sminshall for (p = modes; p->m_name; p++) { 23126095Sminshall printf("%s%s", sep, p->m_name); 23226095Sminshall if (*sep == ' ') 23326095Sminshall sep = " | "; 23426095Sminshall } 23526095Sminshall printf(" ]\n"); 23626095Sminshall return; 2377769Ssam } 2387769Ssam 23926095Sminshall setbinary(argc, argv) 24026095Sminshall char *argv[]; 24126095Sminshall { setmode("octet"); 24226095Sminshall } 24326095Sminshall 24426095Sminshall setascii(argc, argv) 24526095Sminshall char *argv[]; 24626095Sminshall { setmode("netascii"); 24726095Sminshall } 24826095Sminshall 24926095Sminshall setmode(newmode) 25026095Sminshall char *newmode; 25126095Sminshall { 25226095Sminshall strcpy(mode, newmode); 25326095Sminshall if (verbose) 25426095Sminshall printf("mode set to %s\n", mode); 25526095Sminshall } 25626095Sminshall 25726095Sminshall 2587769Ssam /* 2597769Ssam * Send file(s). 2607769Ssam */ 2617769Ssam put(argc, argv) 2627769Ssam char *argv[]; 2637769Ssam { 2647769Ssam int fd; 26526095Sminshall register int n; 2667769Ssam register char *cp, *targ; 2677769Ssam 2687769Ssam if (argc < 2) { 2697769Ssam strcpy(line, "send "); 2707769Ssam printf("(file) "); 2717769Ssam gets(&line[strlen(line)]); 2727769Ssam makeargv(); 2737769Ssam argc = margc; 2747769Ssam argv = margv; 2757769Ssam } 2767769Ssam if (argc < 2) { 2777769Ssam putusage(argv[0]); 2787769Ssam return; 2797769Ssam } 2807769Ssam targ = argv[argc - 1]; 2817769Ssam if (index(argv[argc - 1], ':')) { 2828384Ssam char *cp; 2838384Ssam struct hostent *hp; 2847769Ssam 2857769Ssam for (n = 1; n < argc - 1; n++) 2867769Ssam if (index(argv[n], ':')) { 2877769Ssam putusage(argv[0]); 2887769Ssam return; 2897769Ssam } 2908384Ssam cp = argv[argc - 1]; 2918384Ssam targ = index(cp, ':'); 2927769Ssam *targ++ = 0; 2938384Ssam hp = gethostbyname(cp); 2948384Ssam if (hp == 0) { 2958384Ssam printf("%s: Unknown host.\n", cp); 2967769Ssam return; 2977769Ssam } 2989219Ssam bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 2998384Ssam sin.sin_family = hp->h_addrtype; 3007769Ssam connected = 1; 30126095Sminshall strcpy(hostname, hp->h_name); 3027769Ssam } 3037769Ssam if (!connected) { 3047769Ssam printf("No target machine specified.\n"); 3057769Ssam return; 3067769Ssam } 3077769Ssam if (argc < 4) { 3087769Ssam cp = argc == 2 ? tail(targ) : argv[1]; 30913017Ssam fd = open(cp, O_RDONLY); 3107769Ssam if (fd < 0) { 31113017Ssam fprintf(stderr, "tftp: "); perror(cp); 3127769Ssam return; 3137769Ssam } 31426095Sminshall if (verbose) 31526095Sminshall printf("putting %s to %s:%s [%s]\n", 31626095Sminshall cp, hostname, targ, mode); 31726095Sminshall sin.sin_port = port; 31826095Sminshall sendfile(fd, targ, mode); 3197769Ssam return; 3207769Ssam } 32126095Sminshall /* this assumes the target is a directory */ 32226095Sminshall /* on a remote unix system. hmmmm. */ 3237769Ssam cp = index(targ, '\0'); 3247769Ssam *cp++ = '/'; 3257769Ssam for (n = 1; n < argc - 1; n++) { 3267769Ssam strcpy(cp, tail(argv[n])); 32713017Ssam fd = open(argv[n], O_RDONLY); 3287769Ssam if (fd < 0) { 32913017Ssam fprintf(stderr, "tftp: "); perror(argv[n]); 3307769Ssam continue; 3317769Ssam } 33226095Sminshall if (verbose) 33326095Sminshall printf("putting %s to %s:%s [%s]\n", 33426095Sminshall argv[n], hostname, targ, mode); 33526095Sminshall sin.sin_port = port; 33626095Sminshall sendfile(fd, targ, mode); 3377769Ssam } 3387769Ssam } 3397769Ssam 3407769Ssam putusage(s) 3417769Ssam char *s; 3427769Ssam { 3437769Ssam printf("usage: %s file ... host:target, or\n", s); 3447769Ssam printf(" %s file ... target (when already connected)\n", s); 3457769Ssam } 3467769Ssam 3477769Ssam /* 3487769Ssam * Receive file(s). 3497769Ssam */ 3507769Ssam get(argc, argv) 3517769Ssam char *argv[]; 3527769Ssam { 3537769Ssam int fd; 35426095Sminshall register int n; 3557769Ssam register char *cp; 3567769Ssam char *src; 3577769Ssam 3587769Ssam if (argc < 2) { 3597769Ssam strcpy(line, "get "); 3607769Ssam printf("(files) "); 3617769Ssam gets(&line[strlen(line)]); 3627769Ssam makeargv(); 3637769Ssam argc = margc; 3647769Ssam argv = margv; 3657769Ssam } 3667769Ssam if (argc < 2) { 3677769Ssam getusage(argv[0]); 3687769Ssam return; 3697769Ssam } 37026095Sminshall if (!connected) { 37126095Sminshall for (n = 1; n < argc ; n++) 3727769Ssam if (index(argv[n], ':') == 0) { 3737769Ssam getusage(argv[0]); 3747769Ssam return; 3757769Ssam } 37626095Sminshall } 37726095Sminshall for (n = 1; n < argc ; n++) { 3787769Ssam src = index(argv[n], ':'); 3797769Ssam if (src == NULL) 3807769Ssam src = argv[n]; 3817769Ssam else { 3828384Ssam struct hostent *hp; 3838384Ssam 3847769Ssam *src++ = 0; 3858384Ssam hp = gethostbyname(argv[n]); 3868384Ssam if (hp == 0) { 3877769Ssam printf("%s: Unknown host.\n", argv[n]); 3887769Ssam continue; 3897769Ssam } 3909219Ssam bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 3918384Ssam sin.sin_family = hp->h_addrtype; 3927769Ssam connected = 1; 39326095Sminshall strcpy(hostname, hp->h_name); 3947769Ssam } 3957769Ssam if (argc < 4) { 3967769Ssam cp = argc == 3 ? argv[2] : tail(src); 3977769Ssam fd = creat(cp, 0644); 3987769Ssam if (fd < 0) { 39913017Ssam fprintf(stderr, "tftp: "); perror(cp); 4007769Ssam return; 4017769Ssam } 40226095Sminshall if (verbose) 40326095Sminshall printf("getting from %s:%s to %s [%s]\n", 40426095Sminshall hostname, src, cp, mode); 40526095Sminshall sin.sin_port = port; 40626095Sminshall recvfile(fd, src, mode); 4077769Ssam break; 4087769Ssam } 40926095Sminshall cp = tail(src); /* new .. jdg */ 41026095Sminshall fd = creat(cp, 0644); 4117769Ssam if (fd < 0) { 41226095Sminshall fprintf(stderr, "tftp: "); perror(cp); 4137769Ssam continue; 4147769Ssam } 41526095Sminshall if (verbose) 41626095Sminshall printf("getting from %s:%s to %s [%s]\n", 41726095Sminshall hostname, src, cp, mode); 41826095Sminshall sin.sin_port = port; 41926095Sminshall recvfile(fd, src, mode); 4207769Ssam } 4217769Ssam } 4227769Ssam 4237769Ssam getusage(s) 42426110Sminshall char * s; 4257769Ssam { 4267769Ssam printf("usage: %s host:file host:file ... file, or\n", s); 4277769Ssam printf(" %s file file ... file if connected\n", s); 4287769Ssam } 4297769Ssam 43013017Ssam int rexmtval = TIMEOUT; 43113017Ssam 43213017Ssam setrexmt(argc, argv) 43313017Ssam char *argv[]; 43413017Ssam { 43513017Ssam int t; 43613017Ssam 43713017Ssam if (argc < 2) { 43813017Ssam strcpy(line, "Rexmt-timeout "); 43913017Ssam printf("(value) "); 44013017Ssam gets(&line[strlen(line)]); 44113017Ssam makeargv(); 44213017Ssam argc = margc; 44313017Ssam argv = margv; 44413017Ssam } 44513017Ssam if (argc != 2) { 44613017Ssam printf("usage: %s value\n", argv[0]); 44713017Ssam return; 44813017Ssam } 44913017Ssam t = atoi(argv[1]); 45013017Ssam if (t < 0) 45113017Ssam printf("%s: bad value\n", t); 45213017Ssam else 45313017Ssam rexmtval = t; 45413017Ssam } 45513017Ssam 45613017Ssam int maxtimeout = 5 * TIMEOUT; 45713017Ssam 45813017Ssam settimeout(argc, argv) 45913017Ssam char *argv[]; 46013017Ssam { 46113017Ssam int t; 46213017Ssam 46313017Ssam if (argc < 2) { 46413017Ssam strcpy(line, "Maximum-timeout "); 46513017Ssam printf("(value) "); 46613017Ssam gets(&line[strlen(line)]); 46713017Ssam makeargv(); 46813017Ssam argc = margc; 46913017Ssam argv = margv; 47013017Ssam } 47113017Ssam if (argc != 2) { 47213017Ssam printf("usage: %s value\n", argv[0]); 47313017Ssam return; 47413017Ssam } 47513017Ssam t = atoi(argv[1]); 47613017Ssam if (t < 0) 47713017Ssam printf("%s: bad value\n", t); 47813017Ssam else 47913017Ssam maxtimeout = t; 48013017Ssam } 48113017Ssam 4827769Ssam status(argc, argv) 4837769Ssam char *argv[]; 4847769Ssam { 4857769Ssam if (connected) 4868384Ssam printf("Connected to %s.\n", hostname); 4877769Ssam else 4887769Ssam printf("Not connected.\n"); 48926095Sminshall printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 49026095Sminshall verbose ? "on" : "off", trace ? "on" : "off"); 49113017Ssam printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 49213017Ssam rexmtval, maxtimeout); 4937769Ssam } 4947769Ssam 4957769Ssam intr() 4967769Ssam { 49726095Sminshall signal(SIGALRM, SIG_IGN); 49816382Ssam alarm(0); 4997769Ssam longjmp(toplevel, -1); 5007769Ssam } 5017769Ssam 5027769Ssam char * 5037769Ssam tail(filename) 5047769Ssam char *filename; 5057769Ssam { 5067769Ssam register char *s; 5077769Ssam 5087769Ssam while (*filename) { 5097769Ssam s = rindex(filename, '/'); 5107769Ssam if (s == NULL) 5117769Ssam break; 5127769Ssam if (s[1]) 5137769Ssam return (s + 1); 5147769Ssam *s = '\0'; 5157769Ssam } 5167769Ssam return (filename); 5177769Ssam } 5187769Ssam 5197769Ssam /* 5207769Ssam * Command parser. 5217769Ssam */ 5227769Ssam command(top) 5237769Ssam int top; 5247769Ssam { 5257769Ssam register struct cmd *c; 5267769Ssam 5277769Ssam if (!top) 5287769Ssam putchar('\n'); 5297769Ssam for (;;) { 5307769Ssam printf("%s> ", prompt); 53126103Sminshall if (gets(line) == 0) { 53226103Sminshall if (feof(stdin)) { 53326103Sminshall quit(); 53426103Sminshall } else { 53526103Sminshall continue; 53626103Sminshall } 53726103Sminshall } 5387769Ssam if (line[0] == 0) 53913017Ssam continue; 5407769Ssam makeargv(); 5417769Ssam c = getcmd(margv[0]); 5427769Ssam if (c == (struct cmd *)-1) { 5437769Ssam printf("?Ambiguous command\n"); 5447769Ssam continue; 5457769Ssam } 5467769Ssam if (c == 0) { 5477769Ssam printf("?Invalid command\n"); 5487769Ssam continue; 5497769Ssam } 5507769Ssam (*c->handler)(margc, margv); 5517769Ssam } 5527769Ssam } 5537769Ssam 5547769Ssam struct cmd * 5557769Ssam getcmd(name) 5567769Ssam register char *name; 5577769Ssam { 5587769Ssam register char *p, *q; 5597769Ssam register struct cmd *c, *found; 5607769Ssam register int nmatches, longest; 5617769Ssam 5627769Ssam longest = 0; 5637769Ssam nmatches = 0; 5647769Ssam found = 0; 5657769Ssam for (c = cmdtab; p = c->name; c++) { 5667769Ssam for (q = name; *q == *p++; q++) 5677769Ssam if (*q == 0) /* exact match? */ 5687769Ssam return (c); 5697769Ssam if (!*q) { /* the name was a prefix */ 5707769Ssam if (q - name > longest) { 5717769Ssam longest = q - name; 5727769Ssam nmatches = 1; 5737769Ssam found = c; 5747769Ssam } else if (q - name == longest) 5757769Ssam nmatches++; 5767769Ssam } 5777769Ssam } 5787769Ssam if (nmatches > 1) 5797769Ssam return ((struct cmd *)-1); 5807769Ssam return (found); 5817769Ssam } 5827769Ssam 5837769Ssam /* 5847769Ssam * Slice a string up into argc/argv. 5857769Ssam */ 5867769Ssam makeargv() 5877769Ssam { 5887769Ssam register char *cp; 5897769Ssam register char **argp = margv; 5907769Ssam 5917769Ssam margc = 0; 5927769Ssam for (cp = line; *cp;) { 5937769Ssam while (isspace(*cp)) 5947769Ssam cp++; 5957769Ssam if (*cp == '\0') 5967769Ssam break; 5977769Ssam *argp++ = cp; 5987769Ssam margc += 1; 5997769Ssam while (*cp != '\0' && !isspace(*cp)) 6007769Ssam cp++; 6017769Ssam if (*cp == '\0') 6027769Ssam break; 6037769Ssam *cp++ = '\0'; 6047769Ssam } 6057769Ssam *argp++ = 0; 6067769Ssam } 6077769Ssam 6087769Ssam /*VARARGS*/ 6097769Ssam quit() 6107769Ssam { 6117769Ssam exit(0); 6127769Ssam } 6137769Ssam 6147769Ssam /* 6157769Ssam * Help command. 6167769Ssam */ 6177769Ssam help(argc, argv) 6187769Ssam int argc; 6197769Ssam char *argv[]; 6207769Ssam { 6217769Ssam register struct cmd *c; 6227769Ssam 6237769Ssam if (argc == 1) { 6247769Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 6257769Ssam for (c = cmdtab; c->name; c++) 6267769Ssam printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 6277769Ssam return; 6287769Ssam } 6297769Ssam while (--argc > 0) { 6307769Ssam register char *arg; 6317769Ssam arg = *++argv; 6327769Ssam c = getcmd(arg); 6337769Ssam if (c == (struct cmd *)-1) 6347769Ssam printf("?Ambiguous help command %s\n", arg); 6357769Ssam else if (c == (struct cmd *)0) 6367769Ssam printf("?Invalid help command %s\n", arg); 6377769Ssam else 6387769Ssam printf("%s\n", c->help); 6397769Ssam } 6407769Ssam } 6417769Ssam 6427769Ssam /*VARARGS*/ 6437769Ssam settrace() 6447769Ssam { 6457769Ssam trace = !trace; 6467769Ssam printf("Packet tracing %s.\n", trace ? "on" : "off"); 6477769Ssam } 64826095Sminshall 64926095Sminshall /*VARARGS*/ 65026095Sminshall setverbose() 65126095Sminshall { 65226095Sminshall verbose = !verbose; 65326095Sminshall printf("Verbose mode %s.\n", verbose ? "on" : "off"); 65426095Sminshall } 655