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