122403Sdist /*
2*62309Sbostic * Copyright (c) 1983, 1993
3*62309Sbostic * The Regents of the University of California. All rights reserved.
433821Sbostic *
542770Sbostic * %sccs.include.redist.c%
622403Sdist */
722403Sdist
814553Ssam #ifndef lint
9*62309Sbostic static char copyright[] =
10*62309Sbostic "@(#) Copyright (c) 1983, 1993\n\
11*62309Sbostic The Regents of the University of California. All rights reserved.\n";
1233821Sbostic #endif /* not lint */
137769Ssam
1422403Sdist #ifndef lint
15*62309Sbostic static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/06/93";
1633821Sbostic #endif /* not lint */
1722403Sdist
1826095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
1926095Sminshall
207769Ssam /*
217769Ssam * TFTP User Program -- Command Interface.
227769Ssam */
237769Ssam #include <sys/types.h>
247769Ssam #include <sys/socket.h>
2513017Ssam #include <sys/file.h>
269219Ssam
279219Ssam #include <netinet/in.h>
289219Ssam
2960062Storek #include <arpa/inet.h>
3060062Storek
3160062Storek #include <ctype.h>
3260062Storek #include <errno.h>
3360062Storek #include <netdb.h>
3460062Storek #include <setjmp.h>
357769Ssam #include <signal.h>
367769Ssam #include <stdio.h>
3760062Storek #include <stdlib.h>
3860062Storek #include <string.h>
3960062Storek #include <unistd.h>
407769Ssam
4160062Storek #include "extern.h"
4260062Storek
4313017Ssam #define TIMEOUT 5 /* secs between rexmt's */
4413017Ssam
4560062Storek struct sockaddr_in peeraddr;
467769Ssam int f;
4726095Sminshall short port;
487769Ssam int trace;
4926095Sminshall int verbose;
507769Ssam int connected;
517769Ssam char mode[32];
527769Ssam char line[200];
537769Ssam int margc;
547769Ssam char *margv[20];
557769Ssam char *prompt = "tftp";
567769Ssam jmp_buf toplevel;
5746861Sbostic void intr();
588384Ssam struct servent *sp;
597769Ssam
6060062Storek void get __P((int, char **));
6160062Storek void help __P((int, char **));
6260062Storek void modecmd __P((int, char **));
6360062Storek void put __P((int, char **));
6460062Storek void quit __P((int, char **));
6560062Storek void setascii __P((int, char **));
6660062Storek void setbinary __P((int, char **));
6760062Storek void setpeer __P((int, char **));
6860062Storek void setrexmt __P((int, char **));
6960062Storek void settimeout __P((int, char **));
7060062Storek void settrace __P((int, char **));
7160062Storek void setverbose __P((int, char **));
7260062Storek void status __P((int, char **));
737769Ssam
7460062Storek static __dead void command __P((void));
7560062Storek
7660062Storek static void getusage __P((char *));
7760062Storek static void makeargv __P((void));
7860062Storek static void putusage __P((char *));
7960062Storek static void settftpmode __P((char *));
8060062Storek
817769Ssam #define HELPINDENT (sizeof("connect"))
827769Ssam
837769Ssam struct cmd {
847769Ssam char *name;
857769Ssam char *help;
8660062Storek void (*handler) __P((int, char **));
877769Ssam };
887769Ssam
8926095Sminshall char vhelp[] = "toggle verbose mode";
907769Ssam char thelp[] = "toggle packet tracing";
917769Ssam char chelp[] = "connect to remote tftp";
927769Ssam char qhelp[] = "exit tftp";
937769Ssam char hhelp[] = "print help information";
947769Ssam char shelp[] = "send file";
957769Ssam char rhelp[] = "receive file";
967769Ssam char mhelp[] = "set file transfer mode";
977769Ssam char sthelp[] = "show current status";
9813017Ssam char xhelp[] = "set per-packet retransmission timeout";
9913017Ssam char ihelp[] = "set total retransmission timeout";
10026095Sminshall char ashelp[] = "set mode to netascii";
10126095Sminshall char bnhelp[] = "set mode to octet";
1027769Ssam
1037769Ssam struct cmd cmdtab[] = {
1047769Ssam { "connect", chelp, setpeer },
10526095Sminshall { "mode", mhelp, modecmd },
1067769Ssam { "put", shelp, put },
1077769Ssam { "get", rhelp, get },
1087769Ssam { "quit", qhelp, quit },
10926095Sminshall { "verbose", vhelp, setverbose },
1107769Ssam { "trace", thelp, settrace },
1117769Ssam { "status", sthelp, status },
11226095Sminshall { "binary", bnhelp, setbinary },
11326095Sminshall { "ascii", ashelp, setascii },
11413017Ssam { "rexmt", xhelp, setrexmt },
11513017Ssam { "timeout", ihelp, settimeout },
1167769Ssam { "?", hhelp, help },
11760062Storek { 0 }
1187769Ssam };
1197769Ssam
1207769Ssam struct cmd *getcmd();
1217769Ssam char *tail();
1227769Ssam char *index();
1237769Ssam char *rindex();
1247769Ssam
12560062Storek int
main(argc,argv)1267769Ssam main(argc, argv)
12760062Storek int argc;
1287769Ssam char *argv[];
1297769Ssam {
13026095Sminshall struct sockaddr_in sin;
13113017Ssam
1328384Ssam sp = getservbyname("tftp", "udp");
1338384Ssam if (sp == 0) {
1348384Ssam fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1358384Ssam exit(1);
1368384Ssam }
13726110Sminshall f = socket(AF_INET, SOCK_DGRAM, 0);
1387769Ssam if (f < 0) {
13913017Ssam perror("tftp: socket");
1407769Ssam exit(3);
1417769Ssam }
14260062Storek bzero((char *)&sin, sizeof(sin));
14326095Sminshall sin.sin_family = AF_INET;
14460062Storek if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
14513017Ssam perror("tftp: bind");
14613017Ssam exit(1);
14713017Ssam }
14826095Sminshall strcpy(mode, "netascii");
14913017Ssam signal(SIGINT, intr);
1507769Ssam if (argc > 1) {
1517769Ssam if (setjmp(toplevel) != 0)
1527769Ssam exit(0);
1537769Ssam setpeer(argc, argv);
1547769Ssam }
15560062Storek if (setjmp(toplevel) != 0)
15660062Storek (void)putchar('\n');
15760062Storek command();
1587769Ssam }
1597769Ssam
16026095Sminshall char hostname[100];
1617769Ssam
16260062Storek void
setpeer(argc,argv)1637769Ssam setpeer(argc, argv)
1647769Ssam int argc;
1657769Ssam char *argv[];
1667769Ssam {
1678384Ssam struct hostent *host;
1687769Ssam
1697769Ssam if (argc < 2) {
1707769Ssam strcpy(line, "Connect ");
1717769Ssam printf("(to) ");
1727769Ssam gets(&line[strlen(line)]);
1737769Ssam makeargv();
1747769Ssam argc = margc;
1757769Ssam argv = margv;
1767769Ssam }
1777769Ssam if (argc > 3) {
1787769Ssam printf("usage: %s host-name [port]\n", argv[0]);
1797769Ssam return;
1807769Ssam }
1818384Ssam host = gethostbyname(argv[1]);
1828384Ssam if (host) {
18360062Storek peeraddr.sin_family = host->h_addrtype;
18460062Storek bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
18526095Sminshall strcpy(hostname, host->h_name);
1868384Ssam } else {
18760062Storek peeraddr.sin_family = AF_INET;
18860062Storek peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
18960062Storek if (peeraddr.sin_addr.s_addr == -1) {
1908384Ssam connected = 0;
1918384Ssam printf("%s: unknown host\n", argv[1]);
1928384Ssam return;
1938384Ssam }
19426095Sminshall strcpy(hostname, argv[1]);
1957769Ssam }
19626095Sminshall port = sp->s_port;
1977769Ssam if (argc == 3) {
19826095Sminshall port = atoi(argv[2]);
19926095Sminshall if (port < 0) {
2007769Ssam printf("%s: bad port number\n", argv[2]);
2017769Ssam connected = 0;
2027769Ssam return;
2037769Ssam }
20426095Sminshall port = htons(port);
2058384Ssam }
2067769Ssam connected = 1;
2077769Ssam }
2087769Ssam
2097769Ssam struct modes {
2107769Ssam char *m_name;
2117769Ssam char *m_mode;
2127769Ssam } modes[] = {
21326095Sminshall { "ascii", "netascii" },
21426095Sminshall { "netascii", "netascii" },
21526095Sminshall { "binary", "octet" },
21626095Sminshall { "image", "octet" },
21726103Sminshall { "octet", "octet" },
21826095Sminshall /* { "mail", "mail" }, */
2197769Ssam { 0, 0 }
2207769Ssam };
2217769Ssam
22260062Storek void
modecmd(argc,argv)22326095Sminshall modecmd(argc, argv)
22460062Storek int argc;
2257769Ssam char *argv[];
2267769Ssam {
2277769Ssam register struct modes *p;
22826095Sminshall char *sep;
2297769Ssam
2307769Ssam if (argc < 2) {
2317769Ssam printf("Using %s mode to transfer files.\n", mode);
2327769Ssam return;
2337769Ssam }
23426095Sminshall if (argc == 2) {
23526095Sminshall for (p = modes; p->m_name; p++)
23626095Sminshall if (strcmp(argv[1], p->m_name) == 0)
23726095Sminshall break;
23826095Sminshall if (p->m_name) {
23960062Storek settftpmode(p->m_mode);
24026095Sminshall return;
24126095Sminshall }
2427769Ssam printf("%s: unknown mode\n", argv[1]);
24326095Sminshall /* drop through and print usage message */
24426095Sminshall }
24526095Sminshall
24626095Sminshall printf("usage: %s [", argv[0]);
24726095Sminshall sep = " ";
24826095Sminshall for (p = modes; p->m_name; p++) {
24926095Sminshall printf("%s%s", sep, p->m_name);
25026095Sminshall if (*sep == ' ')
25126095Sminshall sep = " | ";
25226095Sminshall }
25326095Sminshall printf(" ]\n");
25426095Sminshall return;
2557769Ssam }
2567769Ssam
25760062Storek void
setbinary(argc,argv)25826095Sminshall setbinary(argc, argv)
25960062Storek int argc;
26060062Storek char *argv[];
26160062Storek {
26260062Storek
26360062Storek settftpmode("octet");
26426095Sminshall }
26526095Sminshall
26660062Storek void
setascii(argc,argv)26726095Sminshall setascii(argc, argv)
26860062Storek int argc;
26960062Storek char *argv[];
27060062Storek {
27160062Storek
27260062Storek settftpmode("netascii");
27326095Sminshall }
27426095Sminshall
27560062Storek static void
settftpmode(newmode)27660062Storek settftpmode(newmode)
27760062Storek char *newmode;
27826095Sminshall {
27926095Sminshall strcpy(mode, newmode);
28026095Sminshall if (verbose)
28126095Sminshall printf("mode set to %s\n", mode);
28226095Sminshall }
28326095Sminshall
28426095Sminshall
2857769Ssam /*
2867769Ssam * Send file(s).
2877769Ssam */
28860062Storek void
put(argc,argv)2897769Ssam put(argc, argv)
29060062Storek int argc;
2917769Ssam char *argv[];
2927769Ssam {
2937769Ssam int fd;
29426095Sminshall register int n;
2957769Ssam register char *cp, *targ;
2967769Ssam
2977769Ssam if (argc < 2) {
2987769Ssam strcpy(line, "send ");
2997769Ssam printf("(file) ");
3007769Ssam gets(&line[strlen(line)]);
3017769Ssam makeargv();
3027769Ssam argc = margc;
3037769Ssam argv = margv;
3047769Ssam }
3057769Ssam if (argc < 2) {
3067769Ssam putusage(argv[0]);
3077769Ssam return;
3087769Ssam }
3097769Ssam targ = argv[argc - 1];
3107769Ssam if (index(argv[argc - 1], ':')) {
3118384Ssam char *cp;
3128384Ssam struct hostent *hp;
3137769Ssam
3147769Ssam for (n = 1; n < argc - 1; n++)
3157769Ssam if (index(argv[n], ':')) {
3167769Ssam putusage(argv[0]);
3177769Ssam return;
3187769Ssam }
3198384Ssam cp = argv[argc - 1];
3208384Ssam targ = index(cp, ':');
3217769Ssam *targ++ = 0;
3228384Ssam hp = gethostbyname(cp);
32335788Sbostic if (hp == NULL) {
32435788Sbostic fprintf(stderr, "tftp: %s: ", cp);
32535788Sbostic herror((char *)NULL);
3267769Ssam return;
3277769Ssam }
32860062Storek bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
32960062Storek peeraddr.sin_family = hp->h_addrtype;
3307769Ssam connected = 1;
33126095Sminshall strcpy(hostname, hp->h_name);
3327769Ssam }
3337769Ssam if (!connected) {
3347769Ssam printf("No target machine specified.\n");
3357769Ssam return;
3367769Ssam }
3377769Ssam if (argc < 4) {
3387769Ssam cp = argc == 2 ? tail(targ) : argv[1];
33913017Ssam fd = open(cp, O_RDONLY);
3407769Ssam if (fd < 0) {
34113017Ssam fprintf(stderr, "tftp: "); perror(cp);
3427769Ssam return;
3437769Ssam }
34426095Sminshall if (verbose)
34526095Sminshall printf("putting %s to %s:%s [%s]\n",
34626095Sminshall cp, hostname, targ, mode);
34760062Storek peeraddr.sin_port = port;
34826095Sminshall sendfile(fd, targ, mode);
3497769Ssam return;
3507769Ssam }
35126095Sminshall /* this assumes the target is a directory */
35226095Sminshall /* on a remote unix system. hmmmm. */
3537769Ssam cp = index(targ, '\0');
3547769Ssam *cp++ = '/';
3557769Ssam for (n = 1; n < argc - 1; n++) {
3567769Ssam strcpy(cp, tail(argv[n]));
35713017Ssam fd = open(argv[n], O_RDONLY);
3587769Ssam if (fd < 0) {
35913017Ssam fprintf(stderr, "tftp: "); perror(argv[n]);
3607769Ssam continue;
3617769Ssam }
36226095Sminshall if (verbose)
36326095Sminshall printf("putting %s to %s:%s [%s]\n",
36426095Sminshall argv[n], hostname, targ, mode);
36560062Storek peeraddr.sin_port = port;
36626095Sminshall sendfile(fd, targ, mode);
3677769Ssam }
3687769Ssam }
3697769Ssam
37060062Storek static void
putusage(s)3717769Ssam putusage(s)
3727769Ssam char *s;
3737769Ssam {
3747769Ssam printf("usage: %s file ... host:target, or\n", s);
3757769Ssam printf(" %s file ... target (when already connected)\n", s);
3767769Ssam }
3777769Ssam
3787769Ssam /*
3797769Ssam * Receive file(s).
3807769Ssam */
38160062Storek void
get(argc,argv)3827769Ssam get(argc, argv)
38360062Storek int argc;
3847769Ssam char *argv[];
3857769Ssam {
3867769Ssam int fd;
38726095Sminshall register int n;
3887769Ssam register char *cp;
3897769Ssam char *src;
3907769Ssam
3917769Ssam if (argc < 2) {
3927769Ssam strcpy(line, "get ");
3937769Ssam printf("(files) ");
3947769Ssam gets(&line[strlen(line)]);
3957769Ssam makeargv();
3967769Ssam argc = margc;
3977769Ssam argv = margv;
3987769Ssam }
3997769Ssam if (argc < 2) {
4007769Ssam getusage(argv[0]);
4017769Ssam return;
4027769Ssam }
40326095Sminshall if (!connected) {
40426095Sminshall for (n = 1; n < argc ; n++)
4057769Ssam if (index(argv[n], ':') == 0) {
4067769Ssam getusage(argv[0]);
4077769Ssam return;
4087769Ssam }
40926095Sminshall }
41026095Sminshall for (n = 1; n < argc ; n++) {
4117769Ssam src = index(argv[n], ':');
4127769Ssam if (src == NULL)
4137769Ssam src = argv[n];
4147769Ssam else {
4158384Ssam struct hostent *hp;
4168384Ssam
4177769Ssam *src++ = 0;
4188384Ssam hp = gethostbyname(argv[n]);
41935788Sbostic if (hp == NULL) {
42035788Sbostic fprintf(stderr, "tftp: %s: ", argv[n]);
42135788Sbostic herror((char *)NULL);
4227769Ssam continue;
4237769Ssam }
42460062Storek bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
42560062Storek hp->h_length);
42660062Storek peeraddr.sin_family = hp->h_addrtype;
4277769Ssam connected = 1;
42826095Sminshall strcpy(hostname, hp->h_name);
4297769Ssam }
4307769Ssam if (argc < 4) {
4317769Ssam cp = argc == 3 ? argv[2] : tail(src);
4327769Ssam fd = creat(cp, 0644);
4337769Ssam if (fd < 0) {
43413017Ssam fprintf(stderr, "tftp: "); perror(cp);
4357769Ssam return;
4367769Ssam }
43726095Sminshall if (verbose)
43826095Sminshall printf("getting from %s:%s to %s [%s]\n",
43926095Sminshall hostname, src, cp, mode);
44060062Storek peeraddr.sin_port = port;
44126095Sminshall recvfile(fd, src, mode);
4427769Ssam break;
4437769Ssam }
44426095Sminshall cp = tail(src); /* new .. jdg */
44526095Sminshall fd = creat(cp, 0644);
4467769Ssam if (fd < 0) {
44726095Sminshall fprintf(stderr, "tftp: "); perror(cp);
4487769Ssam continue;
4497769Ssam }
45026095Sminshall if (verbose)
45126095Sminshall printf("getting from %s:%s to %s [%s]\n",
45226095Sminshall hostname, src, cp, mode);
45360062Storek peeraddr.sin_port = port;
45426095Sminshall recvfile(fd, src, mode);
4557769Ssam }
4567769Ssam }
4577769Ssam
45860062Storek static void
getusage(s)4597769Ssam getusage(s)
46060062Storek char *s;
4617769Ssam {
4627769Ssam printf("usage: %s host:file host:file ... file, or\n", s);
4637769Ssam printf(" %s file file ... file if connected\n", s);
4647769Ssam }
4657769Ssam
46613017Ssam int rexmtval = TIMEOUT;
46713017Ssam
46860062Storek void
setrexmt(argc,argv)46913017Ssam setrexmt(argc, argv)
47060062Storek int argc;
47113017Ssam char *argv[];
47213017Ssam {
47313017Ssam int t;
47413017Ssam
47513017Ssam if (argc < 2) {
47613017Ssam strcpy(line, "Rexmt-timeout ");
47713017Ssam printf("(value) ");
47813017Ssam gets(&line[strlen(line)]);
47913017Ssam makeargv();
48013017Ssam argc = margc;
48113017Ssam argv = margv;
48213017Ssam }
48313017Ssam if (argc != 2) {
48413017Ssam printf("usage: %s value\n", argv[0]);
48513017Ssam return;
48613017Ssam }
48713017Ssam t = atoi(argv[1]);
48813017Ssam if (t < 0)
48960062Storek printf("%s: bad value\n", argv[1]);
49013017Ssam else
49113017Ssam rexmtval = t;
49213017Ssam }
49313017Ssam
49413017Ssam int maxtimeout = 5 * TIMEOUT;
49513017Ssam
49660062Storek void
settimeout(argc,argv)49713017Ssam settimeout(argc, argv)
49860062Storek int argc;
49913017Ssam char *argv[];
50013017Ssam {
50113017Ssam int t;
50213017Ssam
50313017Ssam if (argc < 2) {
50413017Ssam strcpy(line, "Maximum-timeout ");
50513017Ssam printf("(value) ");
50613017Ssam gets(&line[strlen(line)]);
50713017Ssam makeargv();
50813017Ssam argc = margc;
50913017Ssam argv = margv;
51013017Ssam }
51113017Ssam if (argc != 2) {
51213017Ssam printf("usage: %s value\n", argv[0]);
51313017Ssam return;
51413017Ssam }
51513017Ssam t = atoi(argv[1]);
51613017Ssam if (t < 0)
51760062Storek printf("%s: bad value\n", argv[1]);
51813017Ssam else
51913017Ssam maxtimeout = t;
52013017Ssam }
52113017Ssam
52260062Storek void
status(argc,argv)5237769Ssam status(argc, argv)
52460062Storek int argc;
5257769Ssam char *argv[];
5267769Ssam {
5277769Ssam if (connected)
5288384Ssam printf("Connected to %s.\n", hostname);
5297769Ssam else
5307769Ssam printf("Not connected.\n");
53126095Sminshall printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
53226095Sminshall verbose ? "on" : "off", trace ? "on" : "off");
53313017Ssam printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
53413017Ssam rexmtval, maxtimeout);
5357769Ssam }
5367769Ssam
53746861Sbostic void
intr()5387769Ssam intr()
5397769Ssam {
54060062Storek
54126095Sminshall signal(SIGALRM, SIG_IGN);
54216382Ssam alarm(0);
5437769Ssam longjmp(toplevel, -1);
5447769Ssam }
5457769Ssam
5467769Ssam char *
tail(filename)5477769Ssam tail(filename)
5487769Ssam char *filename;
5497769Ssam {
5507769Ssam register char *s;
5517769Ssam
5527769Ssam while (*filename) {
5537769Ssam s = rindex(filename, '/');
5547769Ssam if (s == NULL)
5557769Ssam break;
5567769Ssam if (s[1])
5577769Ssam return (s + 1);
5587769Ssam *s = '\0';
5597769Ssam }
5607769Ssam return (filename);
5617769Ssam }
5627769Ssam
5637769Ssam /*
5647769Ssam * Command parser.
5657769Ssam */
56660062Storek static __dead void
command()56760062Storek command()
5687769Ssam {
5697769Ssam register struct cmd *c;
5707769Ssam
5717769Ssam for (;;) {
5727769Ssam printf("%s> ", prompt);
57326103Sminshall if (gets(line) == 0) {
57426103Sminshall if (feof(stdin)) {
57560062Storek exit(0);
57626103Sminshall } else {
57726103Sminshall continue;
57826103Sminshall }
57926103Sminshall }
5807769Ssam if (line[0] == 0)
58113017Ssam continue;
5827769Ssam makeargv();
58356221Sandrew if (margc == 0)
58456221Sandrew continue;
5857769Ssam c = getcmd(margv[0]);
5867769Ssam if (c == (struct cmd *)-1) {
5877769Ssam printf("?Ambiguous command\n");
5887769Ssam continue;
5897769Ssam }
5907769Ssam if (c == 0) {
5917769Ssam printf("?Invalid command\n");
5927769Ssam continue;
5937769Ssam }
5947769Ssam (*c->handler)(margc, margv);
5957769Ssam }
5967769Ssam }
5977769Ssam
5987769Ssam struct cmd *
getcmd(name)5997769Ssam getcmd(name)
6007769Ssam register char *name;
6017769Ssam {
6027769Ssam register char *p, *q;
6037769Ssam register struct cmd *c, *found;
6047769Ssam register int nmatches, longest;
6057769Ssam
6067769Ssam longest = 0;
6077769Ssam nmatches = 0;
6087769Ssam found = 0;
60960062Storek for (c = cmdtab; (p = c->name) != NULL; c++) {
6107769Ssam for (q = name; *q == *p++; q++)
6117769Ssam if (*q == 0) /* exact match? */
6127769Ssam return (c);
6137769Ssam if (!*q) { /* the name was a prefix */
6147769Ssam if (q - name > longest) {
6157769Ssam longest = q - name;
6167769Ssam nmatches = 1;
6177769Ssam found = c;
6187769Ssam } else if (q - name == longest)
6197769Ssam nmatches++;
6207769Ssam }
6217769Ssam }
6227769Ssam if (nmatches > 1)
6237769Ssam return ((struct cmd *)-1);
6247769Ssam return (found);
6257769Ssam }
6267769Ssam
6277769Ssam /*
6287769Ssam * Slice a string up into argc/argv.
6297769Ssam */
63060062Storek static void
makeargv()6317769Ssam makeargv()
6327769Ssam {
6337769Ssam register char *cp;
6347769Ssam register char **argp = margv;
6357769Ssam
6367769Ssam margc = 0;
6377769Ssam for (cp = line; *cp;) {
6387769Ssam while (isspace(*cp))
6397769Ssam cp++;
6407769Ssam if (*cp == '\0')
6417769Ssam break;
6427769Ssam *argp++ = cp;
6437769Ssam margc += 1;
6447769Ssam while (*cp != '\0' && !isspace(*cp))
6457769Ssam cp++;
6467769Ssam if (*cp == '\0')
6477769Ssam break;
6487769Ssam *cp++ = '\0';
6497769Ssam }
6507769Ssam *argp++ = 0;
6517769Ssam }
6527769Ssam
65360062Storek void
quit(argc,argv)65460062Storek quit(argc, argv)
65560062Storek int argc;
65660062Storek char *argv[];
6577769Ssam {
65860062Storek
6597769Ssam exit(0);
6607769Ssam }
6617769Ssam
6627769Ssam /*
6637769Ssam * Help command.
6647769Ssam */
66560062Storek void
help(argc,argv)6667769Ssam help(argc, argv)
6677769Ssam int argc;
6687769Ssam char *argv[];
6697769Ssam {
6707769Ssam register struct cmd *c;
6717769Ssam
6727769Ssam if (argc == 1) {
6737769Ssam printf("Commands may be abbreviated. Commands are:\n\n");
6747769Ssam for (c = cmdtab; c->name; c++)
67560062Storek printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
6767769Ssam return;
6777769Ssam }
6787769Ssam while (--argc > 0) {
6797769Ssam register char *arg;
6807769Ssam arg = *++argv;
6817769Ssam c = getcmd(arg);
6827769Ssam if (c == (struct cmd *)-1)
6837769Ssam printf("?Ambiguous help command %s\n", arg);
6847769Ssam else if (c == (struct cmd *)0)
6857769Ssam printf("?Invalid help command %s\n", arg);
6867769Ssam else
6877769Ssam printf("%s\n", c->help);
6887769Ssam }
6897769Ssam }
6907769Ssam
69160062Storek void
settrace(argc,argv)69260062Storek settrace(argc, argv)
69360062Storek int argc;
69460062Storek char **argv;
6957769Ssam {
6967769Ssam trace = !trace;
6977769Ssam printf("Packet tracing %s.\n", trace ? "on" : "off");
6987769Ssam }
69926095Sminshall
70060062Storek void
setverbose(argc,argv)70160062Storek setverbose(argc, argv)
70260062Storek int argc;
70360062Storek char **argv;
70426095Sminshall {
70526095Sminshall verbose = !verbose;
70626095Sminshall printf("Verbose mode %s.\n", verbose ? "on" : "off");
70726095Sminshall }
708