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 634903Sbostic * provided that the above copyright notice and this paragraph are 734903Sbostic * duplicated in all such forms and that any documentation, 834903Sbostic * advertising materials, and other materials related to such 934903Sbostic * distribution and use acknowledge that the software was developed 1034903Sbostic * by the University of California, Berkeley. The name of the 1134903Sbostic * University may not be used to endorse or promote products derived 1234903Sbostic * from this software without specific prior written permission. 1334903Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434903Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534903Sbostic * 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*35788Sbostic static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 10/11/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); 294*35788Sbostic if (hp == NULL) { 295*35788Sbostic fprintf(stderr, "tftp: %s: ", cp); 296*35788Sbostic herror((char *)NULL); 2977769Ssam return; 2987769Ssam } 2999219Ssam bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 3008384Ssam sin.sin_family = hp->h_addrtype; 3017769Ssam connected = 1; 30226095Sminshall strcpy(hostname, hp->h_name); 3037769Ssam } 3047769Ssam if (!connected) { 3057769Ssam printf("No target machine specified.\n"); 3067769Ssam return; 3077769Ssam } 3087769Ssam if (argc < 4) { 3097769Ssam cp = argc == 2 ? tail(targ) : argv[1]; 31013017Ssam fd = open(cp, O_RDONLY); 3117769Ssam if (fd < 0) { 31213017Ssam fprintf(stderr, "tftp: "); perror(cp); 3137769Ssam return; 3147769Ssam } 31526095Sminshall if (verbose) 31626095Sminshall printf("putting %s to %s:%s [%s]\n", 31726095Sminshall cp, hostname, targ, mode); 31826095Sminshall sin.sin_port = port; 31926095Sminshall sendfile(fd, targ, mode); 3207769Ssam return; 3217769Ssam } 32226095Sminshall /* this assumes the target is a directory */ 32326095Sminshall /* on a remote unix system. hmmmm. */ 3247769Ssam cp = index(targ, '\0'); 3257769Ssam *cp++ = '/'; 3267769Ssam for (n = 1; n < argc - 1; n++) { 3277769Ssam strcpy(cp, tail(argv[n])); 32813017Ssam fd = open(argv[n], O_RDONLY); 3297769Ssam if (fd < 0) { 33013017Ssam fprintf(stderr, "tftp: "); perror(argv[n]); 3317769Ssam continue; 3327769Ssam } 33326095Sminshall if (verbose) 33426095Sminshall printf("putting %s to %s:%s [%s]\n", 33526095Sminshall argv[n], hostname, targ, mode); 33626095Sminshall sin.sin_port = port; 33726095Sminshall sendfile(fd, targ, mode); 3387769Ssam } 3397769Ssam } 3407769Ssam 3417769Ssam putusage(s) 3427769Ssam char *s; 3437769Ssam { 3447769Ssam printf("usage: %s file ... host:target, or\n", s); 3457769Ssam printf(" %s file ... target (when already connected)\n", s); 3467769Ssam } 3477769Ssam 3487769Ssam /* 3497769Ssam * Receive file(s). 3507769Ssam */ 3517769Ssam get(argc, argv) 3527769Ssam char *argv[]; 3537769Ssam { 3547769Ssam int fd; 35526095Sminshall register int n; 3567769Ssam register char *cp; 3577769Ssam char *src; 3587769Ssam 3597769Ssam if (argc < 2) { 3607769Ssam strcpy(line, "get "); 3617769Ssam printf("(files) "); 3627769Ssam gets(&line[strlen(line)]); 3637769Ssam makeargv(); 3647769Ssam argc = margc; 3657769Ssam argv = margv; 3667769Ssam } 3677769Ssam if (argc < 2) { 3687769Ssam getusage(argv[0]); 3697769Ssam return; 3707769Ssam } 37126095Sminshall if (!connected) { 37226095Sminshall for (n = 1; n < argc ; n++) 3737769Ssam if (index(argv[n], ':') == 0) { 3747769Ssam getusage(argv[0]); 3757769Ssam return; 3767769Ssam } 37726095Sminshall } 37826095Sminshall for (n = 1; n < argc ; n++) { 3797769Ssam src = index(argv[n], ':'); 3807769Ssam if (src == NULL) 3817769Ssam src = argv[n]; 3827769Ssam else { 3838384Ssam struct hostent *hp; 3848384Ssam 3857769Ssam *src++ = 0; 3868384Ssam hp = gethostbyname(argv[n]); 387*35788Sbostic if (hp == NULL) { 388*35788Sbostic fprintf(stderr, "tftp: %s: ", argv[n]); 389*35788Sbostic herror((char *)NULL); 3907769Ssam continue; 3917769Ssam } 3929219Ssam bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 3938384Ssam sin.sin_family = hp->h_addrtype; 3947769Ssam connected = 1; 39526095Sminshall strcpy(hostname, hp->h_name); 3967769Ssam } 3977769Ssam if (argc < 4) { 3987769Ssam cp = argc == 3 ? argv[2] : tail(src); 3997769Ssam fd = creat(cp, 0644); 4007769Ssam if (fd < 0) { 40113017Ssam fprintf(stderr, "tftp: "); perror(cp); 4027769Ssam return; 4037769Ssam } 40426095Sminshall if (verbose) 40526095Sminshall printf("getting from %s:%s to %s [%s]\n", 40626095Sminshall hostname, src, cp, mode); 40726095Sminshall sin.sin_port = port; 40826095Sminshall recvfile(fd, src, mode); 4097769Ssam break; 4107769Ssam } 41126095Sminshall cp = tail(src); /* new .. jdg */ 41226095Sminshall fd = creat(cp, 0644); 4137769Ssam if (fd < 0) { 41426095Sminshall fprintf(stderr, "tftp: "); perror(cp); 4157769Ssam continue; 4167769Ssam } 41726095Sminshall if (verbose) 41826095Sminshall printf("getting from %s:%s to %s [%s]\n", 41926095Sminshall hostname, src, cp, mode); 42026095Sminshall sin.sin_port = port; 42126095Sminshall recvfile(fd, src, mode); 4227769Ssam } 4237769Ssam } 4247769Ssam 4257769Ssam getusage(s) 42626110Sminshall char * s; 4277769Ssam { 4287769Ssam printf("usage: %s host:file host:file ... file, or\n", s); 4297769Ssam printf(" %s file file ... file if connected\n", s); 4307769Ssam } 4317769Ssam 43213017Ssam int rexmtval = TIMEOUT; 43313017Ssam 43413017Ssam setrexmt(argc, argv) 43513017Ssam char *argv[]; 43613017Ssam { 43713017Ssam int t; 43813017Ssam 43913017Ssam if (argc < 2) { 44013017Ssam strcpy(line, "Rexmt-timeout "); 44113017Ssam printf("(value) "); 44213017Ssam gets(&line[strlen(line)]); 44313017Ssam makeargv(); 44413017Ssam argc = margc; 44513017Ssam argv = margv; 44613017Ssam } 44713017Ssam if (argc != 2) { 44813017Ssam printf("usage: %s value\n", argv[0]); 44913017Ssam return; 45013017Ssam } 45113017Ssam t = atoi(argv[1]); 45213017Ssam if (t < 0) 45313017Ssam printf("%s: bad value\n", t); 45413017Ssam else 45513017Ssam rexmtval = t; 45613017Ssam } 45713017Ssam 45813017Ssam int maxtimeout = 5 * TIMEOUT; 45913017Ssam 46013017Ssam settimeout(argc, argv) 46113017Ssam char *argv[]; 46213017Ssam { 46313017Ssam int t; 46413017Ssam 46513017Ssam if (argc < 2) { 46613017Ssam strcpy(line, "Maximum-timeout "); 46713017Ssam printf("(value) "); 46813017Ssam gets(&line[strlen(line)]); 46913017Ssam makeargv(); 47013017Ssam argc = margc; 47113017Ssam argv = margv; 47213017Ssam } 47313017Ssam if (argc != 2) { 47413017Ssam printf("usage: %s value\n", argv[0]); 47513017Ssam return; 47613017Ssam } 47713017Ssam t = atoi(argv[1]); 47813017Ssam if (t < 0) 47913017Ssam printf("%s: bad value\n", t); 48013017Ssam else 48113017Ssam maxtimeout = t; 48213017Ssam } 48313017Ssam 4847769Ssam status(argc, argv) 4857769Ssam char *argv[]; 4867769Ssam { 4877769Ssam if (connected) 4888384Ssam printf("Connected to %s.\n", hostname); 4897769Ssam else 4907769Ssam printf("Not connected.\n"); 49126095Sminshall printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 49226095Sminshall verbose ? "on" : "off", trace ? "on" : "off"); 49313017Ssam printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", 49413017Ssam rexmtval, maxtimeout); 4957769Ssam } 4967769Ssam 4977769Ssam intr() 4987769Ssam { 49926095Sminshall signal(SIGALRM, SIG_IGN); 50016382Ssam alarm(0); 5017769Ssam longjmp(toplevel, -1); 5027769Ssam } 5037769Ssam 5047769Ssam char * 5057769Ssam tail(filename) 5067769Ssam char *filename; 5077769Ssam { 5087769Ssam register char *s; 5097769Ssam 5107769Ssam while (*filename) { 5117769Ssam s = rindex(filename, '/'); 5127769Ssam if (s == NULL) 5137769Ssam break; 5147769Ssam if (s[1]) 5157769Ssam return (s + 1); 5167769Ssam *s = '\0'; 5177769Ssam } 5187769Ssam return (filename); 5197769Ssam } 5207769Ssam 5217769Ssam /* 5227769Ssam * Command parser. 5237769Ssam */ 5247769Ssam command(top) 5257769Ssam int top; 5267769Ssam { 5277769Ssam register struct cmd *c; 5287769Ssam 5297769Ssam if (!top) 5307769Ssam putchar('\n'); 5317769Ssam for (;;) { 5327769Ssam printf("%s> ", prompt); 53326103Sminshall if (gets(line) == 0) { 53426103Sminshall if (feof(stdin)) { 53526103Sminshall quit(); 53626103Sminshall } else { 53726103Sminshall continue; 53826103Sminshall } 53926103Sminshall } 5407769Ssam if (line[0] == 0) 54113017Ssam continue; 5427769Ssam makeargv(); 5437769Ssam c = getcmd(margv[0]); 5447769Ssam if (c == (struct cmd *)-1) { 5457769Ssam printf("?Ambiguous command\n"); 5467769Ssam continue; 5477769Ssam } 5487769Ssam if (c == 0) { 5497769Ssam printf("?Invalid command\n"); 5507769Ssam continue; 5517769Ssam } 5527769Ssam (*c->handler)(margc, margv); 5537769Ssam } 5547769Ssam } 5557769Ssam 5567769Ssam struct cmd * 5577769Ssam getcmd(name) 5587769Ssam register char *name; 5597769Ssam { 5607769Ssam register char *p, *q; 5617769Ssam register struct cmd *c, *found; 5627769Ssam register int nmatches, longest; 5637769Ssam 5647769Ssam longest = 0; 5657769Ssam nmatches = 0; 5667769Ssam found = 0; 5677769Ssam for (c = cmdtab; p = c->name; c++) { 5687769Ssam for (q = name; *q == *p++; q++) 5697769Ssam if (*q == 0) /* exact match? */ 5707769Ssam return (c); 5717769Ssam if (!*q) { /* the name was a prefix */ 5727769Ssam if (q - name > longest) { 5737769Ssam longest = q - name; 5747769Ssam nmatches = 1; 5757769Ssam found = c; 5767769Ssam } else if (q - name == longest) 5777769Ssam nmatches++; 5787769Ssam } 5797769Ssam } 5807769Ssam if (nmatches > 1) 5817769Ssam return ((struct cmd *)-1); 5827769Ssam return (found); 5837769Ssam } 5847769Ssam 5857769Ssam /* 5867769Ssam * Slice a string up into argc/argv. 5877769Ssam */ 5887769Ssam makeargv() 5897769Ssam { 5907769Ssam register char *cp; 5917769Ssam register char **argp = margv; 5927769Ssam 5937769Ssam margc = 0; 5947769Ssam for (cp = line; *cp;) { 5957769Ssam while (isspace(*cp)) 5967769Ssam cp++; 5977769Ssam if (*cp == '\0') 5987769Ssam break; 5997769Ssam *argp++ = cp; 6007769Ssam margc += 1; 6017769Ssam while (*cp != '\0' && !isspace(*cp)) 6027769Ssam cp++; 6037769Ssam if (*cp == '\0') 6047769Ssam break; 6057769Ssam *cp++ = '\0'; 6067769Ssam } 6077769Ssam *argp++ = 0; 6087769Ssam } 6097769Ssam 6107769Ssam /*VARARGS*/ 6117769Ssam quit() 6127769Ssam { 6137769Ssam exit(0); 6147769Ssam } 6157769Ssam 6167769Ssam /* 6177769Ssam * Help command. 6187769Ssam */ 6197769Ssam help(argc, argv) 6207769Ssam int argc; 6217769Ssam char *argv[]; 6227769Ssam { 6237769Ssam register struct cmd *c; 6247769Ssam 6257769Ssam if (argc == 1) { 6267769Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 6277769Ssam for (c = cmdtab; c->name; c++) 6287769Ssam printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 6297769Ssam return; 6307769Ssam } 6317769Ssam while (--argc > 0) { 6327769Ssam register char *arg; 6337769Ssam arg = *++argv; 6347769Ssam c = getcmd(arg); 6357769Ssam if (c == (struct cmd *)-1) 6367769Ssam printf("?Ambiguous help command %s\n", arg); 6377769Ssam else if (c == (struct cmd *)0) 6387769Ssam printf("?Invalid help command %s\n", arg); 6397769Ssam else 6407769Ssam printf("%s\n", c->help); 6417769Ssam } 6427769Ssam } 6437769Ssam 6447769Ssam /*VARARGS*/ 6457769Ssam settrace() 6467769Ssam { 6477769Ssam trace = !trace; 6487769Ssam printf("Packet tracing %s.\n", trace ? "on" : "off"); 6497769Ssam } 65026095Sminshall 65126095Sminshall /*VARARGS*/ 65226095Sminshall setverbose() 65326095Sminshall { 65426095Sminshall verbose = !verbose; 65526095Sminshall printf("Verbose mode %s.\n", verbose ? "on" : "off"); 65626095Sminshall } 657