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