clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/tftp/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/tftp/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/tftp/main.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | #include <sys/socket.h> |
40 | |
41 | #include <netinet/in.h> |
42 | #include <arpa/inet.h> |
43 | #include <arpa/tftp.h> |
44 | |
45 | #include <ctype.h> |
46 | #include <err.h> |
47 | #include <errno.h> |
48 | #include <fcntl.h> |
49 | #include <netdb.h> |
50 | #include <poll.h> |
51 | #include <signal.h> |
52 | #include <stdio.h> |
53 | #include <stdlib.h> |
54 | #include <string.h> |
55 | #include <unistd.h> |
56 | #include <limits.h> |
57 | |
58 | #include "extern.h" |
59 | |
60 | #define LBUFLEN 200 /* size of input buffer */ |
61 | #define MAXARGV 20 |
62 | #define HELPINDENT (sizeof("connect")) |
63 | |
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 **); |
71 | void setpeer(char *, char *); |
72 | void parsearg(int, char **); |
73 | void setrexmt(int, char **); |
74 | void settimeout(int, char **); |
75 | void settrace(int, char **); |
76 | void setverbose(int, char **); |
77 | void settsize(int, char **); |
78 | void settout(int, char **); |
79 | void setblksize(int, char **); |
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 | |
90 | struct sockaddr_storage peeraddr; |
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[HOST_NAME_MAX+1]; |
104 | FILE *file = NULL; |
105 | volatile sig_atomic_t intrflag = 0; |
106 | char *ackbuf; |
107 | int has_options = 0; |
108 | int opt_tsize = 0; |
109 | int opt_tout = 0; |
110 | int opt_blksize = 0; |
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"; |
123 | char ashelp[] = "set mode to netascii"; |
124 | char bnhelp[] = "set mode to octet"; |
125 | char oshelp[] = "toggle tsize option"; |
126 | char othelp[] = "toggle timeout option"; |
127 | char obhelp[] = "set alternative blksize option"; |
128 | |
129 | struct cmd { |
130 | char *name; |
131 | char *help; |
132 | void (*handler)(int, char **); |
133 | }; |
134 | |
135 | struct cmd cmdtab[] = { |
136 | { "connect", chelp, parsearg }, |
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 }, |
148 | { "tsize", oshelp, settsize }, |
149 | { "tout", othelp, settout }, |
150 | { "blksize", obhelp, setblksize }, |
151 | { "help", hhelp, help }, |
152 | { "?", hhelp, help }, |
153 | { NULL, NULL, NULL } |
154 | }; |
155 | |
156 | struct modes { |
157 | char *m_name; |
158 | char *m_mode; |
159 | } modes[] = { |
160 | { "ascii", "netascii" }, |
161 | { "netascii", "netascii" }, |
162 | { "binary", "octet" }, |
163 | { "image", "octet" }, |
164 | { "octet", "octet" }, |
165 | |
166 | { NULL, NULL } |
167 | }; |
168 | |
169 | int |
170 | main(int argc, char *argv[]) |
171 | { |
172 | f = -1; |
173 | |
174 | if (pledge("stdio rpath wpath cpath dns inet", NULL) == -1) |
175 | err(1, "pledge"); |
176 | |
177 | |
178 | strlcpy(mode, "netascii", sizeof(mode)); |
179 | |
180 | |
181 | if (argc > 1) |
182 | parsearg(argc, argv); |
183 | |
184 | |
185 | signal(SIGINT, intr); |
186 | |
187 | |
188 | if ((ackbuf = malloc(SEGSIZE_MAX + 4)) == NULL) |
189 | err(1, "malloc"); |
190 | |
191 | |
192 | command(); |
193 | |
194 | return (0); |
195 | } |
196 | |
197 | void |
198 | setpeer(char *host, char *port) |
199 | { |
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); |
| 18 | | Value assigned to 'res0' | |
|
219 | if (error) { |
| |
| |
220 | warnx("%s", gai_strerror(error)); |
221 | return; |
222 | } |
223 | |
224 | for (res = res0; res; res = res->ai_next) { |
| 21 | | The value of 'res0' is assigned to 'res' | |
|
| 22 | | Assuming pointer value is null | |
|
| 23 | | Loop condition is false. Execution continues on line 245 | |
|
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 | } |
232 | |
233 | memset(&ss, 0, sizeof(ss)); |
234 | ss.ss_family = res->ai_family; |
235 | if (bind(f, (struct sockaddr *)&ss, res->ai_addrlen) < 0) { |
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 | |
249 | memcpy(&peeraddr, res->ai_addr, res->ai_addrlen); |
| 26 | | Access to field 'ai_addr' results in a dereference of a null pointer (loaded from variable 'res') |
|
250 | if (res->ai_canonname) { |
251 | (void)strlcpy(hostname, res->ai_canonname, |
252 | sizeof(hostname)); |
253 | } else |
254 | (void)strlcpy(hostname, host, sizeof(hostname)); |
255 | connected = 1; |
256 | } |
257 | freeaddrinfo(res0); |
258 | } |
259 | |
260 | void |
261 | parsearg(int argc, char *argv[]) |
262 | { |
263 | if (argc < 2) { |
264 | strlcpy(line, "Connect ", sizeof(line)); |
265 | printf("(to) "); |
266 | readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin); |
267 | if (makeargv()) |
268 | return; |
269 | argc = margc; |
270 | argv = margv; |
271 | } |
272 | if ((argc < 2) || (argc > 3)) { |
273 | printf("usage: %s [host [port]]\n", argv[0]); |
274 | return; |
275 | } |
276 | if (argc == 2) |
277 | setpeer(argv[1], NULL); |
278 | else |
279 | setpeer(argv[1], argv[2]); |
280 | } |
281 | |
282 | void |
283 | modecmd(int argc, char *argv[]) |
284 | { |
285 | struct modes *p; |
286 | char *sep; |
287 | |
288 | if (argc < 2) { |
289 | printf("Using %s mode to transfer files.\n", mode); |
290 | return; |
291 | } |
292 | if (argc == 2) { |
293 | for (p = modes; p->m_name != NULL; p++) |
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 | |
302 | } |
303 | |
304 | printf("usage: %s [", argv[0]); |
305 | sep = " "; |
306 | for (p = modes; p->m_name != NULL; p++) { |
307 | printf("%s%s", sep, p->m_name); |
308 | if (*sep == ' ') |
309 | sep = " | "; |
310 | } |
311 | printf(" ]\n"); |
312 | |
313 | return; |
314 | } |
315 | |
316 | |
317 | void |
318 | setbinary(int argc, char *argv[]) |
319 | { |
320 | settftpmode("octet"); |
321 | } |
322 | |
323 | |
324 | void |
325 | setascii(int argc, char *argv[]) |
326 | { |
327 | settftpmode("netascii"); |
328 | } |
329 | |
330 | static void |
331 | settftpmode(char *newmode) |
332 | { |
333 | strlcpy(mode, newmode, sizeof(mode)); |
334 | if (verbose) |
335 | printf("mode set to %s\n", mode); |
336 | } |
337 | |
338 | |
339 | |
340 | |
341 | void |
342 | put(int argc, char *argv[]) |
343 | { |
344 | int fd; |
345 | int n; |
346 | char *cp, *targ; |
347 | |
348 | if (argc < 2) { |
349 | strlcpy(line, "put ", sizeof(line)); |
350 | printf("(file) "); |
351 | readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin); |
352 | if (makeargv()) |
353 | return; |
354 | argc = margc; |
355 | argv = margv; |
356 | } |
357 | if (argc < 2) { |
358 | putusage(argv[0]); |
359 | return; |
360 | } |
361 | targ = argv[argc - 1]; |
362 | if (strrchr(argv[argc - 1], ':')) { |
363 | |
364 | for (n = 1; n < argc - 1; n++) |
365 | if (strchr(argv[n], ':')) { |
366 | putusage(argv[0]); |
367 | return; |
368 | } |
369 | cp = argv[argc - 1]; |
370 | targ = strrchr(cp, ':'); |
371 | *targ++ = 0; |
372 | if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') { |
373 | cp[strlen(cp) - 1] = '\0'; |
374 | cp++; |
375 | } |
376 | setpeer(cp, NULL); |
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) { |
386 | warn("open: %s", cp); |
387 | return; |
388 | } |
389 | if (verbose) |
390 | printf("putting %s to %s:%s [%s]\n", |
391 | cp, hostname, targ, mode); |
392 | sendfile(fd, targ, mode); |
393 | return; |
394 | } |
395 | |
396 | |
397 | |
398 | |
399 | |
400 | for (n = 1; n < argc - 1; n++) { |
401 | if (asprintf(&cp, "%s/%s", targ, tail(argv[n])) == -1) |
402 | err(1, "asprintf"); |
403 | fd = open(argv[n], O_RDONLY); |
404 | if (fd < 0) { |
405 | warn("open: %s", argv[n]); |
406 | free(cp); |
407 | continue; |
408 | } |
409 | if (verbose) |
410 | printf("putting %s to %s:%s [%s]\n", |
411 | argv[n], hostname, cp, mode); |
412 | sendfile(fd, cp, mode); |
413 | free(cp); |
414 | } |
415 | } |
416 | |
417 | static void |
418 | putusage(char *s) |
419 | { |
420 | printf("usage: %s file [[host:]remotename]\n", s); |
421 | printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", |
422 | s); |
423 | } |
424 | |
425 | |
426 | |
427 | |
428 | void |
429 | get(int argc, char *argv[]) |
430 | { |
431 | int fd; |
432 | int n; |
433 | char *cp; |
434 | char *src; |
435 | |
436 | if (argc < 2) { |
| |
| |
437 | strlcpy(line, "get ", sizeof(line)); |
438 | printf("(files) "); |
439 | readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin); |
440 | if (makeargv()) |
441 | return; |
442 | argc = margc; |
443 | argv = margv; |
444 | } |
445 | if (argc < 2) { |
| |
446 | getusage(argv[0]); |
447 | return; |
448 | } |
449 | if (!connected) { |
| 4 | | Assuming 'connected' is 0 | |
|
| |
450 | for (n = 1; n < argc; n++) |
| 6 | | Loop condition is true. Entering loop body | |
|
| 9 | | Assuming 'n' is >= 'argc' | |
|
| 10 | | Loop condition is false. Execution continues on line 456 | |
|
451 | if (strrchr(argv[n], ':') == 0) { |
| 7 | | Assuming the condition is false | |
|
| |
452 | getusage(argv[0]); |
453 | return; |
454 | } |
455 | } |
456 | for (n = 1; n < argc; n++) { |
| 11 | | Loop condition is true. Entering loop body | |
|
457 | src = strrchr(argv[n], ':'); |
458 | if (src == NULL) |
| 12 | | Assuming 'src' is not equal to NULL | |
|
| |
459 | src = argv[n]; |
460 | else { |
461 | char *cp; |
462 | |
463 | *src++ = 0; |
464 | cp = argv[n]; |
465 | if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') { |
| 14 | | Assuming the condition is false | |
|
466 | cp[strlen(cp) - 1] = '\0'; |
467 | cp++; |
468 | } |
469 | setpeer(cp, NULL); |
| |
470 | if (!connected) |
471 | continue; |
472 | } |
473 | if (argc < 4) { |
474 | cp = argc == 3 ? argv[2] : tail(src); |
475 | fd = open(cp, O_CREAT | O_TRUNC | O_WRONLY, 0644); |
476 | if (fd < 0) { |
477 | warn("create: %s", cp); |
478 | return; |
479 | } |
480 | if (verbose) |
481 | printf("getting from %s:%s to %s [%s]\n", |
482 | hostname, src, cp, mode); |
483 | recvfile(fd, src, mode); |
484 | break; |
485 | } |
486 | cp = tail(src); |
487 | fd = open(cp, O_CREAT | O_TRUNC | O_WRONLY, 0644); |
488 | if (fd < 0) { |
489 | warn("create: %s", cp); |
490 | continue; |
491 | } |
492 | if (verbose) |
493 | printf("getting from %s:%s to %s [%s]\n", |
494 | hostname, src, cp, mode); |
495 | recvfile(fd, src, mode); |
496 | } |
497 | } |
498 | |
499 | static void |
500 | getusage(char *s) |
501 | { |
502 | printf("usage: %s [host:]file [localname]\n", s); |
503 | printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s); |
504 | } |
505 | |
506 | void |
507 | setrexmt(int argc, char *argv[]) |
508 | { |
509 | int t; |
510 | const char *errstr; |
511 | |
512 | if (argc < 2) { |
513 | strlcpy(line, "Rexmt-timeout ", sizeof(line)); |
514 | printf("(value) "); |
515 | readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin); |
516 | if (makeargv()) |
517 | return; |
518 | argc = margc; |
519 | argv = margv; |
520 | } |
521 | if (argc != 2) { |
522 | printf("usage: %s value\n", argv[0]); |
523 | return; |
524 | } |
525 | t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr); |
526 | if (errstr) |
527 | printf("%s: value is %s\n", argv[1], errstr); |
528 | else |
529 | rexmtval = t; |
530 | } |
531 | |
532 | void |
533 | settimeout(int argc, char *argv[]) |
534 | { |
535 | int t; |
536 | const char *errstr; |
537 | |
538 | if (argc < 2) { |
539 | strlcpy(line, "Maximum-timeout ", sizeof(line)); |
540 | printf("(value) "); |
541 | readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin); |
542 | if (makeargv()) |
543 | return; |
544 | argc = margc; |
545 | argv = margv; |
546 | } |
547 | if (argc != 2) { |
548 | printf("usage: %s value\n", argv[0]); |
549 | return; |
550 | } |
551 | t = strtonum(argv[1], TIMEOUT_MIN, TIMEOUT_MAX, &errstr); |
552 | if (errstr) |
553 | printf("%s: value is %s\n", argv[1], errstr); |
554 | else |
555 | maxtimeout = t; |
556 | } |
557 | |
558 | |
559 | void |
560 | status(int argc, char *argv[]) |
561 | { |
562 | if (connected) |
563 | printf("Connected to %s.\n", hostname); |
564 | else |
565 | printf("Not connected.\n"); |
566 | printf("Mode: %s Verbose: %s Tracing: %s\n", |
567 | mode, verbose ? "on" : "off", trace ? "on" : "off"); |
568 | printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", |
569 | rexmtval, maxtimeout); |
570 | } |
571 | |
572 | |
573 | void |
574 | intr(int signo) |
575 | { |
576 | intrflag = 1; |
577 | } |
578 | |
579 | char * |
580 | tail(char *filename) |
581 | { |
582 | char *s; |
583 | |
584 | while (*filename) { |
585 | s = strrchr(filename, '/'); |
586 | if (s == NULL) |
587 | break; |
588 | if (s[1]) |
589 | return (s + 1); |
590 | *s = '\0'; |
591 | } |
592 | |
593 | return (filename); |
594 | } |
595 | |
596 | |
597 | |
598 | |
599 | static __dead void |
600 | command(void) |
601 | { |
602 | struct cmd *c; |
603 | |
604 | for (;;) { |
605 | printf("%s> ", prompt); |
606 | if (readcmd(line, LBUFLEN, stdin) < 1) |
607 | continue; |
608 | if ((line[0] == 0) || (line[0] == '\n')) |
609 | continue; |
610 | if (makeargv()) |
611 | continue; |
612 | if (margc == 0) |
613 | continue; |
614 | c = getcmd(margv[0]); |
615 | if (c == (struct cmd *) - 1) { |
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 * |
628 | getcmd(char *name) |
629 | { |
630 | char *p, *q; |
631 | struct cmd *c, *found; |
632 | int nmatches, longest; |
633 | |
634 | longest = 0; |
635 | nmatches = 0; |
636 | found = 0; |
637 | intrflag = 0; |
638 | for (c = cmdtab; (p = c->name) != NULL; c++) { |
639 | for (q = name; *q == *p++; q++) |
640 | if (*q == 0) |
641 | return (c); |
642 | if (!*q) { |
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) |
652 | return ((struct cmd *) - 1); |
653 | |
654 | return (found); |
655 | } |
656 | |
657 | |
658 | |
659 | |
660 | static int |
661 | makeargv(void) |
662 | { |
663 | char *cp; |
664 | char **argp = margv; |
665 | int ret = 0; |
666 | |
667 | margc = 0; |
668 | for (cp = line; *cp;) { |
669 | if (margc >= MAXARGV) { |
670 | printf("too many arguments\n"); |
671 | ret = 1; |
672 | break; |
673 | } |
674 | while (isspace((unsigned char)*cp)) |
675 | cp++; |
676 | if (*cp == '\0') |
677 | break; |
678 | *argp++ = cp; |
679 | margc += 1; |
680 | while (*cp != '\0' && !isspace((unsigned char)*cp)) |
681 | cp++; |
682 | if (*cp == '\0') |
683 | break; |
684 | *cp++ = '\0'; |
685 | } |
686 | *argp++ = 0; |
687 | |
688 | return (ret); |
689 | } |
690 | |
691 | |
692 | void |
693 | quit(int argc, char *argv[]) |
694 | { |
695 | exit(0); |
696 | } |
697 | |
698 | |
699 | |
700 | |
701 | void |
702 | help(int argc, char *argv[]) |
703 | { |
704 | struct cmd *c; |
705 | |
706 | if (argc == 1) { |
707 | printf("Commands may be abbreviated. Commands are:\n\n"); |
708 | for (c = cmdtab; c->name != NULL; c++) |
709 | printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); |
710 | return; |
711 | } |
712 | while (--argc > 0) { |
713 | char *arg; |
714 | arg = *++argv; |
715 | c = getcmd(arg); |
716 | if (c == (struct cmd *) - 1) |
717 | printf("?Ambiguous help command %s\n", arg); |
718 | else if (c == NULL) |
719 | printf("?Invalid help command %s\n", arg); |
720 | else |
721 | printf("%s\n", c->help); |
722 | } |
723 | } |
724 | |
725 | |
726 | void |
727 | settrace(int argc, char *argv[]) |
728 | { |
729 | trace = !trace; |
730 | printf("Packet tracing %s.\n", trace ? "on" : "off"); |
731 | } |
732 | |
733 | |
734 | void |
735 | setverbose(int argc, char *argv[]) |
736 | { |
737 | verbose = !verbose; |
738 | printf("Verbose mode %s.\n", verbose ? "on" : "off"); |
739 | } |
740 | |
741 | |
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 | |
753 | |
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 | } |
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); |
822 | } |