Annotation of src/usr.bin/tftp/main.c, Revision 1.28
1.28 ! mglocker 1: /* $OpenBSD: main.c,v 1.27 2006/07/26 09:10:03 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.28 ! mglocker 44: "$OpenBSD: main.c,v 1.27 2006/07/26 09:10:03 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.28 ! mglocker 225: const char *errstr;
1.1 deraadt 226:
227: if (argc < 2) {
1.25 mglocker 228: strlcpy(line, "Connect ", sizeof(line));
1.1 deraadt 229: printf("(to) ");
1.25 mglocker 230: readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5 deraadt 231: if (makeargv())
232: return;
1.1 deraadt 233: argc = margc;
234: argv = margv;
235: }
236: if ((argc < 2) || (argc > 3)) {
1.20 jmc 237: printf("usage: %s [host [port]]\n", argv[0]);
1.1 deraadt 238: return;
239: }
240: if (inet_aton(argv[1], &peeraddr.sin_addr) != 0) {
241: peeraddr.sin_family = AF_INET;
1.25 mglocker 242: (void)strncpy(hostname, argv[1], sizeof(hostname));
243: hostname[sizeof(hostname) - 1] = '\0';
1.1 deraadt 244: } else {
245: host = gethostbyname(argv[1]);
246: if (host == 0) {
247: connected = 0;
248: printf("%s: unknown host\n", argv[1]);
249: return;
250: }
251: peeraddr.sin_family = host->h_addrtype;
252: bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
1.25 mglocker 253: (void)strlcpy(hostname, host->h_name, sizeof(hostname));
1.1 deraadt 254: }
255: port = sp->s_port;
256: if (argc == 3) {
1.28 ! mglocker 257: port = strtonum(argv[2], 1, 65535, &errstr);
! 258: if (errstr) {
! 259: printf("%s: port number is %s\n", argv[2], errstr);
1.1 deraadt 260: connected = 0;
261: return;
262: }
263: port = htons(port);
264: }
265: connected = 1;
266: }
267:
268: void
1.14 deraadt 269: modecmd(int argc, char *argv[])
1.1 deraadt 270: {
1.25 mglocker 271: struct modes *p;
272: char *sep;
1.1 deraadt 273:
274: if (argc < 2) {
275: printf("Using %s mode to transfer files.\n", mode);
276: return;
277: }
278: if (argc == 2) {
1.8 mpech 279: for (p = modes; p->m_name != NULL; p++)
1.1 deraadt 280: if (strcmp(argv[1], p->m_name) == 0)
281: break;
282: if (p->m_name) {
283: settftpmode(p->m_mode);
284: return;
285: }
286: printf("%s: unknown mode\n", argv[1]);
287: /* drop through and print usage message */
288: }
289:
290: printf("usage: %s [", argv[0]);
291: sep = " ";
1.8 mpech 292: for (p = modes; p->m_name != NULL; p++) {
1.1 deraadt 293: printf("%s%s", sep, p->m_name);
294: if (*sep == ' ')
295: sep = " | ";
296: }
297: printf(" ]\n");
1.25 mglocker 298:
1.1 deraadt 299: return;
300: }
301:
302: void
1.14 deraadt 303: setbinary(int argc, char *argv[])
1.6 mickey 304: {
1.1 deraadt 305: settftpmode("octet");
306: }
307:
308: void
1.14 deraadt 309: setascii(int argc, char *argv[])
1.1 deraadt 310: {
311: settftpmode("netascii");
312: }
313:
314: static void
1.14 deraadt 315: settftpmode(char *newmode)
1.1 deraadt 316: {
1.25 mglocker 317: strlcpy(mode, newmode, sizeof(mode));
1.1 deraadt 318: if (verbose)
319: printf("mode set to %s\n", mode);
320: }
321:
322: /*
323: * Send file(s).
324: */
325: void
1.14 deraadt 326: put(int argc, char *argv[])
1.1 deraadt 327: {
1.25 mglocker 328: int fd;
329: int n;
330: char *cp, *targ;
1.1 deraadt 331:
332: if (argc < 2) {
1.25 mglocker 333: strlcpy(line, "send ", sizeof(line));
1.1 deraadt 334: printf("(file) ");
1.24 claudio 335: readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5 deraadt 336: if (makeargv())
337: return;
1.1 deraadt 338: argc = margc;
339: argv = margv;
340: }
341: if (argc < 2) {
342: putusage(argv[0]);
343: return;
344: }
345: targ = argv[argc - 1];
1.4 millert 346: if (strchr(argv[argc - 1], ':')) {
1.25 mglocker 347: char *cp;
348: struct hostent *hp;
1.1 deraadt 349:
350: for (n = 1; n < argc - 1; n++)
1.4 millert 351: if (strchr(argv[n], ':')) {
1.1 deraadt 352: putusage(argv[0]);
353: return;
354: }
355: cp = argv[argc - 1];
1.4 millert 356: targ = strchr(cp, ':');
1.1 deraadt 357: *targ++ = 0;
358: hp = gethostbyname(cp);
359: if (hp == NULL) {
1.6 mickey 360: warnx("%s: %s", cp, hstrerror(h_errno));
1.1 deraadt 361: return;
362: }
363: bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
364: peeraddr.sin_family = hp->h_addrtype;
365: connected = 1;
1.17 deraadt 366: port = sp->s_port;
1.25 mglocker 367: strlcpy(hostname, hp->h_name, sizeof(hostname));
1.1 deraadt 368: }
369: if (!connected) {
370: printf("No target machine specified.\n");
371: return;
372: }
373: if (argc < 4) {
374: cp = argc == 2 ? tail(targ) : argv[1];
375: fd = open(cp, O_RDONLY);
376: if (fd < 0) {
1.6 mickey 377: warn("open: %s", cp);
1.1 deraadt 378: return;
379: }
380: if (verbose)
381: printf("putting %s to %s:%s [%s]\n",
1.18 deraadt 382: cp, hostname, targ, mode);
1.1 deraadt 383: peeraddr.sin_port = port;
384: sendfile(fd, targ, mode);
385: return;
386: }
1.18 deraadt 387:
1.24 claudio 388: /*
389: * this assumes the target is a directory on
390: * on a remote unix system. hmmmm.
391: */
1.1 deraadt 392: for (n = 1; n < argc - 1; n++) {
1.12 henning 393: if (asprintf(&cp, "%s/%s", targ, tail(argv[n])) == -1)
394: err(1, "asprintf");
1.1 deraadt 395: fd = open(argv[n], O_RDONLY);
396: if (fd < 0) {
1.6 mickey 397: warn("open: %s", argv[n]);
1.22 mpech 398: free(cp);
1.1 deraadt 399: continue;
400: }
401: if (verbose)
402: printf("putting %s to %s:%s [%s]\n",
1.18 deraadt 403: argv[n], hostname, cp, mode);
1.1 deraadt 404: peeraddr.sin_port = port;
1.12 henning 405: sendfile(fd, cp, mode);
406: free(cp);
1.1 deraadt 407: }
408: }
409:
410: static void
1.14 deraadt 411: putusage(char *s)
1.1 deraadt 412: {
1.19 jmc 413: printf("usage: %s file [[host:]remotename]\n", s);
1.24 claudio 414: printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n",
415: s);
1.1 deraadt 416: }
417:
418: /*
419: * Receive file(s).
420: */
421: void
1.14 deraadt 422: get(int argc, char *argv[])
1.1 deraadt 423: {
1.25 mglocker 424: int fd;
425: int n;
426: char *cp;
427: char *src;
1.1 deraadt 428:
429: if (argc < 2) {
1.25 mglocker 430: strlcpy(line, "get ", sizeof(line));
1.1 deraadt 431: printf("(files) ");
1.25 mglocker 432: readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5 deraadt 433: if (makeargv())
434: return;
1.1 deraadt 435: argc = margc;
436: argv = margv;
437: }
438: if (argc < 2) {
439: getusage(argv[0]);
440: return;
441: }
442: if (!connected) {
1.25 mglocker 443: for (n = 1; n < argc; n++)
1.4 millert 444: if (strchr(argv[n], ':') == 0) {
1.1 deraadt 445: getusage(argv[0]);
446: return;
447: }
448: }
1.25 mglocker 449: for (n = 1; n < argc; n++) {
1.4 millert 450: src = strchr(argv[n], ':');
1.1 deraadt 451: if (src == NULL)
452: src = argv[n];
453: else {
1.25 mglocker 454: struct hostent *hp;
1.1 deraadt 455:
456: *src++ = 0;
457: hp = gethostbyname(argv[n]);
458: if (hp == NULL) {
1.6 mickey 459: warnx("%s: %s", argv[n], hstrerror(h_errno));
1.1 deraadt 460: continue;
461: }
462: bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
463: hp->h_length);
464: peeraddr.sin_family = hp->h_addrtype;
465: connected = 1;
1.25 mglocker 466: strlcpy(hostname, hp->h_name, sizeof(hostname));
1.1 deraadt 467: }
468: if (argc < 4) {
469: cp = argc == 3 ? argv[2] : tail(src);
470: fd = creat(cp, 0644);
471: if (fd < 0) {
1.6 mickey 472: warn("create: %s", cp);
1.1 deraadt 473: return;
474: }
475: if (verbose)
476: printf("getting from %s:%s to %s [%s]\n",
1.18 deraadt 477: hostname, src, cp, mode);
1.1 deraadt 478: peeraddr.sin_port = port;
479: recvfile(fd, src, mode);
480: break;
481: }
1.25 mglocker 482: cp = tail(src); /* new .. jdg */
1.1 deraadt 483: fd = creat(cp, 0644);
484: if (fd < 0) {
1.6 mickey 485: warn("create: %s", cp);
1.1 deraadt 486: continue;
487: }
488: if (verbose)
489: printf("getting from %s:%s to %s [%s]\n",
1.18 deraadt 490: hostname, src, cp, mode);
1.1 deraadt 491: peeraddr.sin_port = port;
492: recvfile(fd, src, mode);
493: }
494: }
495:
496: static void
1.15 deraadt 497: getusage(char *s)
1.1 deraadt 498: {
1.19 jmc 499: printf("usage: %s [host:]file [localname]\n", s);
500: printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
1.1 deraadt 501: }
502:
503: void
1.14 deraadt 504: setrexmt(int argc, char *argv[])
1.1 deraadt 505: {
1.26 mglocker 506: int t;
507: const char *errstr;
1.1 deraadt 508:
509: if (argc < 2) {
1.25 mglocker 510: strlcpy(line, "Rexmt-timeout ", sizeof(line));
1.1 deraadt 511: printf("(value) ");
1.25 mglocker 512: readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5 deraadt 513: if (makeargv())
514: return;
1.1 deraadt 515: argc = margc;
516: argv = margv;
517: }
518: if (argc != 2) {
519: printf("usage: %s value\n", argv[0]);
520: return;
521: }
1.27 mglocker 522: t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
1.26 mglocker 523: if (errstr)
524: printf("%s: value is %s\n", argv[1], errstr);
1.1 deraadt 525: else
526: rexmtval = t;
527: }
528:
529: void
1.14 deraadt 530: settimeout(int argc, char *argv[])
1.1 deraadt 531: {
1.27 mglocker 532: int t;
533: const char *errstr;
1.1 deraadt 534:
535: if (argc < 2) {
1.25 mglocker 536: strlcpy(line, "Maximum-timeout ", sizeof(line));
1.1 deraadt 537: printf("(value) ");
1.25 mglocker 538: readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
1.5 deraadt 539: if (makeargv())
540: return;
1.1 deraadt 541: argc = margc;
542: argv = margv;
543: }
544: if (argc != 2) {
545: printf("usage: %s value\n", argv[0]);
546: return;
547: }
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: }