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