Annotation of src/usr.bin/tftp/main.c, Revision 1.44
1.44 ! kn 1: /* $OpenBSD: main.c,v 1.43 2018/09/20 11:42:42 jsg 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.43 jsg 255: connected = 1;
1.31 gsoares 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 (;;) {
1.44 ! kn 605: if (isatty(STDIN_FILENO))
! 606: printf("%s> ", prompt);
1.24 claudio 607: if (readcmd(line, LBUFLEN, stdin) < 1)
608: continue;
1.1 deraadt 609: if ((line[0] == 0) || (line[0] == '\n'))
610: continue;
1.5 deraadt 611: if (makeargv())
612: continue;
1.1 deraadt 613: if (margc == 0)
614: continue;
615: c = getcmd(margv[0]);
1.25 mglocker 616: if (c == (struct cmd *) - 1) {
1.1 deraadt 617: printf("?Ambiguous command\n");
618: continue;
619: }
620: if (c == 0) {
621: printf("?Invalid command\n");
622: continue;
623: }
624: (*c->handler)(margc, margv);
625: }
626: }
627:
628: struct cmd *
1.14 deraadt 629: getcmd(char *name)
1.1 deraadt 630: {
1.25 mglocker 631: char *p, *q;
632: struct cmd *c, *found;
633: int nmatches, longest;
1.1 deraadt 634:
635: longest = 0;
636: nmatches = 0;
637: found = 0;
1.24 claudio 638: intrflag = 0;
1.1 deraadt 639: for (c = cmdtab; (p = c->name) != NULL; c++) {
640: for (q = name; *q == *p++; q++)
641: if (*q == 0) /* exact match? */
642: return (c);
643: if (!*q) { /* the name was a prefix */
644: if (q - name > longest) {
645: longest = q - name;
646: nmatches = 1;
647: found = c;
648: } else if (q - name == longest)
649: nmatches++;
650: }
651: }
652: if (nmatches > 1)
1.25 mglocker 653: return ((struct cmd *) - 1);
654:
1.1 deraadt 655: return (found);
656: }
657:
658: /*
659: * Slice a string up into argc/argv.
660: */
1.5 deraadt 661: static int
1.14 deraadt 662: makeargv(void)
1.1 deraadt 663: {
1.25 mglocker 664: char *cp;
665: char **argp = margv;
666: int ret = 0;
1.1 deraadt 667:
668: margc = 0;
669: for (cp = line; *cp;) {
1.5 deraadt 670: if (margc >= MAXARGV) {
671: printf("too many arguments\n");
672: ret = 1;
673: break;
674: }
1.34 deraadt 675: while (isspace((unsigned char)*cp))
1.1 deraadt 676: cp++;
677: if (*cp == '\0')
678: break;
679: *argp++ = cp;
680: margc += 1;
1.34 deraadt 681: while (*cp != '\0' && !isspace((unsigned char)*cp))
1.1 deraadt 682: cp++;
683: if (*cp == '\0')
684: break;
685: *cp++ = '\0';
686: }
687: *argp++ = 0;
1.25 mglocker 688:
1.5 deraadt 689: return (ret);
1.1 deraadt 690: }
691:
1.29 ray 692: /* ARGSUSED */
1.1 deraadt 693: void
1.14 deraadt 694: quit(int argc, char *argv[])
1.1 deraadt 695: {
696: exit(0);
697: }
698:
699: /*
700: * Help command.
701: */
702: void
1.14 deraadt 703: help(int argc, char *argv[])
1.1 deraadt 704: {
1.25 mglocker 705: struct cmd *c;
1.1 deraadt 706:
707: if (argc == 1) {
708: printf("Commands may be abbreviated. Commands are:\n\n");
1.8 mpech 709: for (c = cmdtab; c->name != NULL; c++)
1.1 deraadt 710: printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
711: return;
712: }
713: while (--argc > 0) {
1.9 mpech 714: char *arg;
1.1 deraadt 715: arg = *++argv;
716: c = getcmd(arg);
1.25 mglocker 717: if (c == (struct cmd *) - 1)
1.1 deraadt 718: printf("?Ambiguous help command %s\n", arg);
1.40 krw 719: else if (c == NULL)
1.1 deraadt 720: printf("?Invalid help command %s\n", arg);
721: else
722: printf("%s\n", c->help);
723: }
724: }
725:
1.29 ray 726: /* ARGSUSED */
1.1 deraadt 727: void
1.14 deraadt 728: settrace(int argc, char *argv[])
1.1 deraadt 729: {
730: trace = !trace;
731: printf("Packet tracing %s.\n", trace ? "on" : "off");
732: }
733:
1.29 ray 734: /* ARGSUSED */
1.1 deraadt 735: void
1.14 deraadt 736: setverbose(int argc, char *argv[])
1.1 deraadt 737: {
738: verbose = !verbose;
739: printf("Verbose mode %s.\n", verbose ? "on" : "off");
1.26 mglocker 740: }
741:
1.29 ray 742: /* ARGSUSED */
1.26 mglocker 743: void
744: settsize(int argc, char *argv[])
745: {
746: opt_tsize = !opt_tsize;
747: printf("Tsize option %s.\n", opt_tsize ? "on" : "off");
748: if (opt_tsize)
749: has_options++;
750: else
751: has_options--;
752: }
753:
1.29 ray 754: /* ARGSUSED */
1.26 mglocker 755: void
756: settout(int argc, char *argv[])
757: {
758: opt_tout = !opt_tout;
759: printf("Timeout option %s.\n", opt_tout ? "on" : "off");
760: if (opt_tout)
761: has_options++;
762: else
763: has_options--;
764: }
765:
766: void
767: setblksize(int argc, char *argv[])
768: {
769: int t;
770: const char *errstr;
771:
772: if (argc < 2) {
773: strlcpy(line, "Blocksize ", sizeof(line));
774: printf("(value) ");
775: readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin);
776: if (makeargv())
777: return;
778: argc = margc;
779: argv = margv;
780: }
781: if (argc != 2) {
782: printf("usage: %s value\n", argv[0]);
783: return;
784: }
785: t = strtonum(argv[1], SEGSIZE_MIN, SEGSIZE_MAX, &errstr);
786: if (errstr)
787: printf("%s: value is %s\n", argv[1], errstr);
788: else {
789: if (opt_blksize == 0)
790: has_options++;
791: opt_blksize = t;
792: }
1.24 claudio 793: }
794:
795: int
796: readcmd(char *input, int len, FILE *stream)
797: {
798: int nfds;
799: struct pollfd pfd[1];
800:
801: fflush(stdout);
802:
803: pfd[0].fd = 0;
804: pfd[0].events = POLLIN;
805: nfds = poll(pfd, 1, INFTIM);
806: if (nfds == -1) {
807: if (intrflag) {
808: intrflag = 0;
809: putchar('\n');
810: return (0);
811: }
812: exit(1);
813: }
814:
815: if (fgets(input, len, stream) == NULL) {
816: if (feof(stdin))
817: exit(0);
818: else
819: return (-1);
820: }
821:
822: return (1);
1.1 deraadt 823: }