main.c (1b0fa6fa40ecc6b97e9fbdea630ba2bdbe632077) main.c (752fa694029c20397f7928fa5f6b80f787677be2)
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 40 unchanged lines hidden (view full) ---

49/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
50
51/*
52 * TFTP User Program -- Command Interface.
53 */
54#include <sys/param.h>
55#include <sys/types.h>
56#include <sys/socket.h>
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 40 unchanged lines hidden (view full) ---

49/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
50
51/*
52 * TFTP User Program -- Command Interface.
53 */
54#include <sys/param.h>
55#include <sys/types.h>
56#include <sys/socket.h>
57#include <sys/sysctl.h>
57#include <sys/file.h>
58#include <sys/param.h>
58#include <sys/file.h>
59#include <sys/param.h>
60#include <sys/stat.h>
59
60#include <netinet/in.h>
61
62#include <netinet/in.h>
61
62#include <arpa/inet.h>
63#include <arpa/inet.h>
64#include <arpa/tftp.h>
63
64#include <ctype.h>
65#include <err.h>
66#include <histedit.h>
67#include <netdb.h>
68#include <setjmp.h>
69#include <signal.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74
65
66#include <ctype.h>
67#include <err.h>
68#include <histedit.h>
69#include <netdb.h>
70#include <setjmp.h>
71#include <signal.h>
72#include <stdio.h>
73#include <stdlib.h>
74#include <string.h>
75#include <unistd.h>
76
75#include "extern.h"
77#include "tftp-utils.h"
78#include "tftp-io.h"
79#include "tftp-options.h"
80#include "tftp.h"
76
77#define MAXLINE 200
78#define TIMEOUT 5 /* secs between rexmt's */
79
81
82#define MAXLINE 200
83#define TIMEOUT 5 /* secs between rexmt's */
84
80struct sockaddr_storage peeraddr;
81int f;
82int trace;
83int verbose;
84int connected;
85char mode[32];
86char line[MAXLINE];
87int margc;
85static struct sockaddr_storage peeraddr;
86static int connected;
87static char mode[32];
88jmp_buf toplevel;
89volatile int txrx_error;
90static int peer;
91
88#define MAX_MARGV 20
92#define MAX_MARGV 20
89char *margv[MAX_MARGV];
90jmp_buf toplevel;
91volatile int txrx_error;
93static int margc;
94static char *margv[MAX_MARGV];
92
95
93void get(int, char **);
94void help(int, char **);
95void intr(int);
96void modecmd(int, char **);
97void put(int, char **);
98void quit(int, char **);
99void setascii(int, char **);
100void setbinary(int, char **);
101void setpeer0(char *, const char *);
102void setpeer(int, char **);
103void setrexmt(int, char **);
104void settimeout(int, char **);
105void settrace(int, char **);
106void setverbose(int, char **);
107void status(int, char **);
96int verbose;
97char *port = NULL;
108
98
99static void get(int, char **);
100static void help(int, char **);
101static void intr(int);
102static void modecmd(int, char **);
103static void put(int, char **);
104static void quit(int, char **);
105static void setascii(int, char **);
106static void setbinary(int, char **);
107static void setpeer0(char *, const char *);
108static void setpeer(int, char **);
109static void settimeoutpacket(int, char **);
110static void settimeoutnetwork(int, char **);
111static void setdebug(int, char **);
112static void setverbose(int, char **);
113static void showstatus(int, char **);
114static void setblocksize(int, char **);
115static void setblocksize2(int, char **);
116static void setoptions(int, char **);
117static void setrollover(int, char **);
118static void setpacketdrop(int, char **);
119
109static void command(void) __dead2;
110static const char *command_prompt(void);
111
120static void command(void) __dead2;
121static const char *command_prompt(void);
122
112static void getusage(const char *);
113static void makeargv(void);
114static void putusage(const char *);
123static void urihandling(char *URI);
124static void getusage(char *);
125static void makeargv(char *line);
126static void putusage(char *);
115static void settftpmode(const char *);
116
127static void settftpmode(const char *);
128
117char *tail(char *);
118struct cmd *getcmd(char *);
129static char *tail(char *);
130static struct cmd *getcmd(char *);
119
120#define HELPINDENT (sizeof("connect"))
121
122struct cmd {
123 const char *name;
131
132#define HELPINDENT (sizeof("connect"))
133
134struct cmd {
135 const char *name;
124 char *help;
125 void (*handler)(int, char **);
136 void (*handler)(int, char **);
137 const char *help;
126};
127
138};
139
128char vhelp[] = "toggle verbose mode";
129char thelp[] = "toggle packet tracing";
130char chelp[] = "connect to remote tftp";
131char qhelp[] = "exit tftp";
132char hhelp[] = "print help information";
133char shelp[] = "send file";
134char rhelp[] = "receive file";
135char mhelp[] = "set file transfer mode";
136char sthelp[] = "show current status";
137char xhelp[] = "set per-packet retransmission timeout";
138char ihelp[] = "set total retransmission timeout";
139char ashelp[] = "set mode to netascii";
140char bnhelp[] = "set mode to octet";
140static struct cmd cmdtab[] = {
141 { "connect", setpeer, "connect to remote tftp" },
142 { "mode", modecmd, "set file transfer mode" },
143 { "put", put, "send file" },
144 { "get", get, "receive file" },
145 { "quit", quit, "exit tftp" },
146 { "verbose", setverbose, "toggle verbose mode" },
147 { "status", showstatus, "show current status" },
148 { "binary", setbinary, "set mode to octet" },
149 { "ascii", setascii, "set mode to netascii" },
150 { "rexmt", settimeoutpacket,
151 "set per-packet retransmission timeout[-]" },
152 { "timeout", settimeoutnetwork,
153 "set total retransmission timeout" },
154 { "trace", setdebug, "enable 'debug packet'[-]" },
155 { "debug", setdebug, "enable verbose output" },
156 { "blocksize", setblocksize, "set blocksize[*]" },
157 { "blocksize2", setblocksize2, "set blocksize as a power of 2[**]" },
158 { "rollover", setrollover, "rollover after 64K packets[**]" },
159 { "options", setoptions,
160 "enable or disable RFC2347 style options" },
161 { "help", help, "print help information" },
162 { "packetdrop", setpacketdrop, "artifical packetloss feature" },
163 { "?", help, "print help information" },
164 { NULL, NULL, NULL }
165};
141
166
142struct cmd cmdtab[] = {
143 { "connect", chelp, setpeer },
144 { "mode", mhelp, modecmd },
145 { "put", shelp, put },
146 { "get", rhelp, get },
147 { "quit", qhelp, quit },
148 { "verbose", vhelp, setverbose },
149 { "trace", thelp, settrace },
150 { "status", sthelp, status },
151 { "binary", bnhelp, setbinary },
152 { "ascii", ashelp, setascii },
153 { "rexmt", xhelp, setrexmt },
154 { "timeout", ihelp, settimeout },
155 { "?", hhelp, help },
156 { NULL, NULL, NULL }
167static struct modes {
168 const char *m_name;
169 const char *m_mode;
170} modes[] = {
171 { "ascii", "netascii" },
172 { "netascii", "netascii" },
173 { "binary", "octet" },
174 { "image", "octet" },
175 { "octet", "octet" },
176 { NULL, NULL }
157};
158
159int
160main(int argc, char *argv[])
161{
177};
178
179int
180main(int argc, char *argv[])
181{
162 f = -1;
182
183 acting_as_client = 1;
184 peer = -1;
163 strcpy(mode, "netascii");
164 signal(SIGINT, intr);
165 if (argc > 1) {
166 if (setjmp(toplevel) != 0)
167 exit(txrx_error);
185 strcpy(mode, "netascii");
186 signal(SIGINT, intr);
187 if (argc > 1) {
188 if (setjmp(toplevel) != 0)
189 exit(txrx_error);
190
191 if (strncmp(argv[1], "tftp://", 7) == 0) {
192 urihandling(argv[1]);
193 exit(txrx_error);
194 }
195
168 setpeer(argc, argv);
169 }
170 if (setjmp(toplevel) != 0)
171 (void)putchar('\n');
196 setpeer(argc, argv);
197 }
198 if (setjmp(toplevel) != 0)
199 (void)putchar('\n');
200
201 init_options();
172 command();
173}
174
202 command();
203}
204
175char hostname[MAXHOSTNAMELEN];
205/*
206 * RFC3617 handling of TFTP URIs:
207 *
208 * tftpURI = "tftp://" host "/" file [ mode ]
209 * mode = ";" "mode=" ( "netascii" / "octet" )
210 * file = *( unreserved / escaped )
211 * host = <as specified by RFC 2732>
212 * unreserved = <as specified in RFC 2396>
213 * escaped = <as specified in RFC 2396>
214 *
215 * We are cheating a little bit by allowing any mode as specified in the
216 * modes table defined earlier on in this file and mapping it on the real
217 * mode.
218 */
219static void
220urihandling(char *URI)
221{
222 char uri[ARG_MAX];
223 char *host = NULL;
224 char *path = NULL;
225 char *options = NULL;
226 char *mode = "octet";
227 char *s;
228 char line[MAXLINE];
229 int i;
176
230
177void
178setpeer0(char *host, const char *port)
231 strncpy(uri, URI, ARG_MAX);
232 host = uri + 7;
233
234 if ((s = strchr(host, '/')) == NULL) {
235 fprintf(stderr,
236 "Invalid URI: Couldn't find / after hostname\n");
237 exit(1);
238 }
239 *s = '\0';
240 path = s + 1;
241
242 if ((s = strchr(path, ';')) != NULL) {
243 *s = '\0';
244 options = s + 1;
245
246 if (strncmp(options, "mode=", 5) == 0) {
247 mode = options;
248 mode += 5;
249
250 for (i = 0; modes[i].m_name != NULL; i++) {
251 if (strcmp(modes[i].m_name, mode) == 0)
252 break;
253 }
254 if (modes[i].m_name == NULL) {
255 fprintf(stderr, "Invalid mode: '%s'\n", mode);
256 exit(1);
257 }
258 settftpmode(modes[i].m_mode);
259 }
260 } else {
261 settftpmode("octet");
262 }
263
264 setpeer0(host, NULL);
265
266 sprintf(line, "get %s", path);
267 makeargv(line);
268 get(margc, margv);
269}
270
271static char hostname[MAXHOSTNAMELEN];
272
273static void
274setpeer0(char *host, const char *lport)
179{
180 struct addrinfo hints, *res0, *res;
181 int error;
275{
276 struct addrinfo hints, *res0, *res;
277 int error;
182 struct sockaddr_storage ss;
183 const char *cause = "unknown";
184
185 if (connected) {
278 const char *cause = "unknown";
279
280 if (connected) {
186 close(f);
187 f = -1;
281 close(peer);
282 peer = -1;
188 }
189 connected = 0;
190
191 memset(&hints, 0, sizeof(hints));
192 hints.ai_family = PF_UNSPEC;
193 hints.ai_socktype = SOCK_DGRAM;
194 hints.ai_protocol = IPPROTO_UDP;
195 hints.ai_flags = AI_CANONNAME;
283 }
284 connected = 0;
285
286 memset(&hints, 0, sizeof(hints));
287 hints.ai_family = PF_UNSPEC;
288 hints.ai_socktype = SOCK_DGRAM;
289 hints.ai_protocol = IPPROTO_UDP;
290 hints.ai_flags = AI_CANONNAME;
196 if (!port)
197 port = "tftp";
198 error = getaddrinfo(host, port, &hints, &res0);
291 if (!lport)
292 lport = "tftp";
293 error = getaddrinfo(host, lport, &hints, &res0);
199 if (error) {
200 warnx("%s", gai_strerror(error));
201 return;
202 }
203
204 for (res = res0; res; res = res->ai_next) {
205 if (res->ai_addrlen > sizeof(peeraddr))
206 continue;
294 if (error) {
295 warnx("%s", gai_strerror(error));
296 return;
297 }
298
299 for (res = res0; res; res = res->ai_next) {
300 if (res->ai_addrlen > sizeof(peeraddr))
301 continue;
207 f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
208 if (f < 0) {
302 peer = socket(res->ai_family, res->ai_socktype,
303 res->ai_protocol);
304 if (peer < 0) {
209 cause = "socket";
210 continue;
211 }
212
305 cause = "socket";
306 continue;
307 }
308
213 memset(&ss, 0, sizeof(ss));
214 ss.ss_family = res->ai_family;
215 ss.ss_len = res->ai_addrlen;
216 if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
309 memset(&peer_sock, 0, sizeof(peer_sock));
310 peer_sock.ss_family = res->ai_family;
311 peer_sock.ss_len = res->ai_addrlen;
312 if (bind(peer, (struct sockaddr *)&peer_sock, peer_sock.ss_len) < 0) {
217 cause = "bind";
313 cause = "bind";
218 close(f);
219 f = -1;
314 close(peer);
315 peer = -1;
220 continue;
221 }
222
223 break;
224 }
225
316 continue;
317 }
318
319 break;
320 }
321
226 if (f < 0)
322 if (peer < 0)
227 warn("%s", cause);
228 else {
229 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
323 warn("%s", cause);
324 else {
325 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
230 memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
326 memcpy(&peer_sock, res->ai_addr, res->ai_addrlen);
231 if (res->ai_canonname) {
327 if (res->ai_canonname) {
232 (void) strlcpy(hostname, res->ai_canonname,
328 (void) strncpy(hostname, res->ai_canonname,
233 sizeof(hostname));
234 } else
329 sizeof(hostname));
330 } else
235 (void) strlcpy(hostname, host, sizeof(hostname));
331 (void) strncpy(hostname, host, sizeof(hostname));
332 hostname[sizeof(hostname)-1] = 0;
236 connected = 1;
237 }
238
239 freeaddrinfo(res0);
240}
241
333 connected = 1;
334 }
335
336 freeaddrinfo(res0);
337}
338
242void
339static void
243setpeer(int argc, char *argv[])
244{
340setpeer(int argc, char *argv[])
341{
342 char line[MAXLINE];
245
246 if (argc < 2) {
247 strcpy(line, "Connect ");
248 printf("(to) ");
249 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
343
344 if (argc < 2) {
345 strcpy(line, "Connect ");
346 printf("(to) ");
347 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
250 makeargv();
348 makeargv(line);
251 argc = margc;
252 argv = margv;
253 }
254 if ((argc < 2) || (argc > 3)) {
255 printf("usage: %s [host [port]]\n", argv[0]);
256 return;
257 }
349 argc = margc;
350 argv = margv;
351 }
352 if ((argc < 2) || (argc > 3)) {
353 printf("usage: %s [host [port]]\n", argv[0]);
354 return;
355 }
258 if (argc == 3)
356 if (argc == 3) {
357 port = argv[2];
259 setpeer0(argv[1], argv[2]);
358 setpeer0(argv[1], argv[2]);
260 else
359 } else
261 setpeer0(argv[1], NULL);
262}
263
360 setpeer0(argv[1], NULL);
361}
362
264struct modes {
265 const char *m_name;
266 const char *m_mode;
267} modes[] = {
268 { "ascii", "netascii" },
269 { "netascii", "netascii" },
270 { "binary", "octet" },
271 { "image", "octet" },
272 { "octet", "octet" },
273/* { "mail", "mail" }, */
274 { 0, 0 }
275};
276
277void
363static void
278modecmd(int argc, char *argv[])
279{
280 struct modes *p;
281 const char *sep;
282
283 if (argc < 2) {
284 printf("Using %s mode to transfer files.\n", mode);
285 return;

--- 7 unchanged lines hidden (view full) ---

293 return;
294 }
295 printf("%s: unknown mode\n", argv[1]);
296 /* drop through and print usage message */
297 }
298
299 printf("usage: %s [", argv[0]);
300 sep = " ";
364modecmd(int argc, char *argv[])
365{
366 struct modes *p;
367 const char *sep;
368
369 if (argc < 2) {
370 printf("Using %s mode to transfer files.\n", mode);
371 return;

--- 7 unchanged lines hidden (view full) ---

379 return;
380 }
381 printf("%s: unknown mode\n", argv[1]);
382 /* drop through and print usage message */
383 }
384
385 printf("usage: %s [", argv[0]);
386 sep = " ";
301 for (p = modes; p->m_name; p++) {
387 for (p = modes; p->m_name != NULL; p++) {
302 printf("%s%s", sep, p->m_name);
303 if (*sep == ' ')
304 sep = " | ";
305 }
306 printf(" ]\n");
307 return;
308}
309
388 printf("%s%s", sep, p->m_name);
389 if (*sep == ' ')
390 sep = " | ";
391 }
392 printf(" ]\n");
393 return;
394}
395
310void
396static void
311setbinary(int argc __unused, char *argv[] __unused)
312{
313
314 settftpmode("octet");
315}
316
397setbinary(int argc __unused, char *argv[] __unused)
398{
399
400 settftpmode("octet");
401}
402
317void
403static void
318setascii(int argc __unused, char *argv[] __unused)
319{
320
321 settftpmode("netascii");
322}
323
324static void
325settftpmode(const char *newmode)
326{
404setascii(int argc __unused, char *argv[] __unused)
405{
406
407 settftpmode("netascii");
408}
409
410static void
411settftpmode(const char *newmode)
412{
413
327 strcpy(mode, newmode);
328 if (verbose)
329 printf("mode set to %s\n", mode);
330}
331
332
333/*
334 * Send file(s).
335 */
414 strcpy(mode, newmode);
415 if (verbose)
416 printf("mode set to %s\n", mode);
417}
418
419
420/*
421 * Send file(s).
422 */
336void
423static void
337put(int argc, char *argv[])
338{
424put(int argc, char *argv[])
425{
339 int fd;
340 int n;
341 char *cp, *targ;
426 int fd;
427 int n;
428 char *cp, *targ;
429 char line[MAXLINE];
430 struct stat sb;
342
343 if (argc < 2) {
344 strcpy(line, "send ");
345 printf("(file) ");
346 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
431
432 if (argc < 2) {
433 strcpy(line, "send ");
434 printf("(file) ");
435 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
347 makeargv();
436 makeargv(line);
348 argc = margc;
349 argv = margv;
350 }
351 if (argc < 2) {
352 putusage(argv[0]);
353 return;
354 }
355 targ = argv[argc - 1];

--- 20 unchanged lines hidden (view full) ---

376 }
377 if (argc < 4) {
378 cp = argc == 2 ? tail(targ) : argv[1];
379 fd = open(cp, O_RDONLY);
380 if (fd < 0) {
381 warn("%s", cp);
382 return;
383 }
437 argc = margc;
438 argv = margv;
439 }
440 if (argc < 2) {
441 putusage(argv[0]);
442 return;
443 }
444 targ = argv[argc - 1];

--- 20 unchanged lines hidden (view full) ---

465 }
466 if (argc < 4) {
467 cp = argc == 2 ? tail(targ) : argv[1];
468 fd = open(cp, O_RDONLY);
469 if (fd < 0) {
470 warn("%s", cp);
471 return;
472 }
473
474 stat(cp, &sb);
475 asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size);
476
384 if (verbose)
385 printf("putting %s to %s:%s [%s]\n",
477 if (verbose)
478 printf("putting %s to %s:%s [%s]\n",
386 cp, hostname, targ, mode);
387 xmitfile(fd, targ, mode);
479 cp, hostname, targ, mode);
480 xmitfile(peer, port, fd, targ, mode);
388 return;
389 }
390 /* this assumes the target is a directory */
391 /* on a remote unix system. hmmmm. */
392 cp = index(targ, '\0');
393 *cp++ = '/';
394 for (n = 1; n < argc - 1; n++) {
395 strcpy(cp, tail(argv[n]));
396 fd = open(argv[n], O_RDONLY);
397 if (fd < 0) {
398 warn("%s", argv[n]);
399 continue;
400 }
481 return;
482 }
483 /* this assumes the target is a directory */
484 /* on a remote unix system. hmmmm. */
485 cp = index(targ, '\0');
486 *cp++ = '/';
487 for (n = 1; n < argc - 1; n++) {
488 strcpy(cp, tail(argv[n]));
489 fd = open(argv[n], O_RDONLY);
490 if (fd < 0) {
491 warn("%s", argv[n]);
492 continue;
493 }
494
495 stat(cp, &sb);
496 asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size);
497
401 if (verbose)
402 printf("putting %s to %s:%s [%s]\n",
498 if (verbose)
499 printf("putting %s to %s:%s [%s]\n",
403 argv[n], hostname, targ, mode);
404 xmitfile(fd, targ, mode);
500 argv[n], hostname, targ, mode);
501 xmitfile(peer, port, fd, targ, mode);
405 }
406}
407
408static void
502 }
503}
504
505static void
409putusage(const char *s)
506putusage(char *s)
410{
507{
411 printf("usage: %s file [[host:]remotename]\n", s);
508
509 printf("usage: %s file [remotename]\n", s);
510 printf(" %s file host:remotename\n", s);
412 printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s);
413}
414
415/*
416 * Receive file(s).
417 */
511 printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s);
512}
513
514/*
515 * Receive file(s).
516 */
418void
517static void
419get(int argc, char *argv[])
420{
421 int fd;
422 int n;
423 char *cp;
424 char *src;
518get(int argc, char *argv[])
519{
520 int fd;
521 int n;
522 char *cp;
523 char *src;
524 char line[MAXLINE];
425
426 if (argc < 2) {
427 strcpy(line, "get ");
428 printf("(files) ");
429 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
525
526 if (argc < 2) {
527 strcpy(line, "get ");
528 printf("(files) ");
529 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
430 makeargv();
530 makeargv(line);
431 argc = margc;
432 argv = margv;
433 }
434 if (argc < 2) {
435 getusage(argv[0]);
436 return;
437 }
438 if (!connected) {
439 for (n = 1; n < argc ; n++)
440 if (rindex(argv[n], ':') == 0) {
531 argc = margc;
532 argv = margv;
533 }
534 if (argc < 2) {
535 getusage(argv[0]);
536 return;
537 }
538 if (!connected) {
539 for (n = 1; n < argc ; n++)
540 if (rindex(argv[n], ':') == 0) {
541 printf("No remote host specified and "
542 "no host given for file '%s'\n", argv[n]);
441 getusage(argv[0]);
442 return;
443 }
444 }
445 for (n = 1; n < argc ; n++) {
446 src = rindex(argv[n], ':');
447 if (src == NULL)
448 src = argv[n];

--- 14 unchanged lines hidden (view full) ---

463 cp = argc == 3 ? argv[2] : tail(src);
464 fd = creat(cp, 0644);
465 if (fd < 0) {
466 warn("%s", cp);
467 return;
468 }
469 if (verbose)
470 printf("getting from %s:%s to %s [%s]\n",
543 getusage(argv[0]);
544 return;
545 }
546 }
547 for (n = 1; n < argc ; n++) {
548 src = rindex(argv[n], ':');
549 if (src == NULL)
550 src = argv[n];

--- 14 unchanged lines hidden (view full) ---

565 cp = argc == 3 ? argv[2] : tail(src);
566 fd = creat(cp, 0644);
567 if (fd < 0) {
568 warn("%s", cp);
569 return;
570 }
571 if (verbose)
572 printf("getting from %s:%s to %s [%s]\n",
471 hostname, src, cp, mode);
472 recvfile(fd, src, mode);
573 hostname, src, cp, mode);
574 recvfile(peer, port, fd, src, mode);
473 break;
474 }
475 cp = tail(src); /* new .. jdg */
476 fd = creat(cp, 0644);
477 if (fd < 0) {
478 warn("%s", cp);
479 continue;
480 }
481 if (verbose)
482 printf("getting from %s:%s to %s [%s]\n",
575 break;
576 }
577 cp = tail(src); /* new .. jdg */
578 fd = creat(cp, 0644);
579 if (fd < 0) {
580 warn("%s", cp);
581 continue;
582 }
583 if (verbose)
584 printf("getting from %s:%s to %s [%s]\n",
483 hostname, src, cp, mode);
484 recvfile(fd, src, mode);
585 hostname, src, cp, mode);
586 recvfile(peer, port, fd, src, mode);
485 }
486}
487
488static void
587 }
588}
589
590static void
489getusage(const char *s)
591getusage(char *s)
490{
592{
491 printf("usage: %s [host:]file [localname]\n", s);
593
594 printf("usage: %s file [localname]\n", s);
595 printf(" %s [host:]file [localname]\n", s);
492 printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
493}
494
596 printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
597}
598
495int rexmtval = TIMEOUT;
496
497void
498setrexmt(int argc, char *argv[])
599static void
600settimeoutpacket(int argc, char *argv[])
499{
500 int t;
601{
602 int t;
603 char line[MAXLINE];
501
502 if (argc < 2) {
604
605 if (argc < 2) {
503 strcpy(line, "Rexmt-timeout ");
606 strcpy(line, "Packet timeout ");
504 printf("(value) ");
505 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
607 printf("(value) ");
608 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
506 makeargv();
609 makeargv(line);
507 argc = margc;
508 argv = margv;
509 }
510 if (argc != 2) {
511 printf("usage: %s value\n", argv[0]);
512 return;
513 }
514 t = atoi(argv[1]);
610 argc = margc;
611 argv = margv;
612 }
613 if (argc != 2) {
614 printf("usage: %s value\n", argv[0]);
615 return;
616 }
617 t = atoi(argv[1]);
515 if (t < 0)
618 if (t < 0) {
516 printf("%s: bad value\n", argv[1]);
619 printf("%s: bad value\n", argv[1]);
517 else
518 rexmtval = t;
620 return;
621 }
622
623 settimeouts(t, timeoutnetwork, maxtimeouts);
519}
520
624}
625
521int maxtimeout = 5 * TIMEOUT;
522
523void
524settimeout(int argc, char *argv[])
626static void
627settimeoutnetwork(int argc, char *argv[])
525{
526 int t;
628{
629 int t;
630 char line[MAXLINE];
527
528 if (argc < 2) {
631
632 if (argc < 2) {
529 strcpy(line, "Maximum-timeout ");
633 strcpy(line, "Network timeout ");
530 printf("(value) ");
531 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
634 printf("(value) ");
635 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
532 makeargv();
636 makeargv(line);
533 argc = margc;
534 argv = margv;
535 }
536 if (argc != 2) {
537 printf("usage: %s value\n", argv[0]);
538 return;
539 }
540 t = atoi(argv[1]);
637 argc = margc;
638 argv = margv;
639 }
640 if (argc != 2) {
641 printf("usage: %s value\n", argv[0]);
642 return;
643 }
644 t = atoi(argv[1]);
541 if (t < 0)
645 if (t < 0) {
542 printf("%s: bad value\n", argv[1]);
646 printf("%s: bad value\n", argv[1]);
543 else
544 maxtimeout = t;
647 return;
648 }
649
650 settimeouts(timeoutpacket, t, maxtimeouts);
545}
546
651}
652
547void
548status(int argc __unused, char *argv[] __unused)
653static void
654showstatus(int argc __unused, char *argv[] __unused)
549{
655{
550 if (connected)
551 printf("Connected to %s.\n", hostname);
552 else
553 printf("Not connected.\n");
554 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
555 verbose ? "on" : "off", trace ? "on" : "off");
556 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
557 rexmtval, maxtimeout);
656
657 printf("Remote host: %s\n",
658 connected ? hostname : "none specified yet");
659 printf("RFC2347 Options support: %s\n",
660 options_rfc_enabled ? "enabled" : "disabled");
661 printf("Non-RFC defined options support: %s\n",
662 options_extra_enabled ? "enabled" : "disabled");
663 printf("Mode: %s\n", mode);
664 printf("Verbose: %s\n", verbose ? "on" : "off");
665 printf("Debug: %s\n", debug_show(debug));
666 printf("Artificial packetloss: %d in 100 packets\n",
667 packetdroppercentage);
668 printf("Segment size: %d bytes\n", segsize);
669 printf("Network timeout: %d seconds\n", timeoutpacket);
670 printf("Maximum network timeout: %d seconds\n", timeoutnetwork);
671 printf("Maximum timeouts: %d \n", maxtimeouts);
558}
559
672}
673
560void
674static void
561intr(int dummy __unused)
562{
563
564 signal(SIGALRM, SIG_IGN);
565 alarm(0);
566 longjmp(toplevel, -1);
567}
568
675intr(int dummy __unused)
676{
677
678 signal(SIGALRM, SIG_IGN);
679 alarm(0);
680 longjmp(toplevel, -1);
681}
682
569char *
683static char *
570tail(char *filename)
571{
572 char *s;
573
574 while (*filename) {
575 s = rindex(filename, '/');
576 if (s == NULL)
577 break;
578 if (s[1])
579 return (s + 1);
580 *s = '\0';
581 }
582 return (filename);
583}
584
585static const char *
684tail(char *filename)
685{
686 char *s;
687
688 while (*filename) {
689 s = rindex(filename, '/');
690 if (s == NULL)
691 break;
692 if (s[1])
693 return (s + 1);
694 *s = '\0';
695 }
696 return (filename);
697}
698
699static const char *
586command_prompt(void)
700command_prompt()
587{
588
589 return ("tftp> ");
590}
591
592/*
593 * Command parser.
594 */
595static void
596command(void)
597{
598 HistEvent he;
599 struct cmd *c;
600 static EditLine *el;
601 static History *hist;
602 const char *bp;
603 char *cp;
604 int len, num, vrbose;
701{
702
703 return ("tftp> ");
704}
705
706/*
707 * Command parser.
708 */
709static void
710command(void)
711{
712 HistEvent he;
713 struct cmd *c;
714 static EditLine *el;
715 static History *hist;
716 const char *bp;
717 char *cp;
718 int len, num, vrbose;
719 char line[MAXLINE];
605
606 vrbose = isatty(0);
607 if (vrbose) {
608 el = el_init("tftp", stdin, stdout, stderr);
609 hist = history_init();
610 history(hist, &he, H_SETSIZE, 100);
611 el_set(el, EL_HIST, history, hist);
612 el_set(el, EL_EDITOR, "emacs");

--- 5 unchanged lines hidden (view full) ---

618 if (vrbose) {
619 if ((bp = el_gets(el, &num)) == NULL || num == 0)
620 exit(0);
621 len = (num > MAXLINE) ? MAXLINE : num;
622 memcpy(line, bp, len);
623 line[len] = '\0';
624 history(hist, &he, H_ENTER, bp);
625 } else {
720
721 vrbose = isatty(0);
722 if (vrbose) {
723 el = el_init("tftp", stdin, stdout, stderr);
724 hist = history_init();
725 history(hist, &he, H_SETSIZE, 100);
726 el_set(el, EL_HIST, history, hist);
727 el_set(el, EL_EDITOR, "emacs");

--- 5 unchanged lines hidden (view full) ---

733 if (vrbose) {
734 if ((bp = el_gets(el, &num)) == NULL || num == 0)
735 exit(0);
736 len = (num > MAXLINE) ? MAXLINE : num;
737 memcpy(line, bp, len);
738 line[len] = '\0';
739 history(hist, &he, H_ENTER, bp);
740 } else {
741 line[0] = 0;
626 if (fgets(line, sizeof line , stdin) == 0) {
627 if (feof(stdin)) {
628 exit(txrx_error);
629 } else {
630 continue;
631 }
632 }
633 }
634 if ((cp = strchr(line, '\n')))
635 *cp = '\0';
636 if (line[0] == 0)
637 continue;
742 if (fgets(line, sizeof line , stdin) == 0) {
743 if (feof(stdin)) {
744 exit(txrx_error);
745 } else {
746 continue;
747 }
748 }
749 }
750 if ((cp = strchr(line, '\n')))
751 *cp = '\0';
752 if (line[0] == 0)
753 continue;
638 makeargv();
754 makeargv(line);
639 if (margc == 0)
640 continue;
641 c = getcmd(margv[0]);
642 if (c == (struct cmd *)-1) {
643 printf("?Ambiguous command\n");
644 continue;
645 }
646 if (c == 0) {
647 printf("?Invalid command\n");
648 continue;
649 }
650 (*c->handler)(margc, margv);
651 }
652}
653
755 if (margc == 0)
756 continue;
757 c = getcmd(margv[0]);
758 if (c == (struct cmd *)-1) {
759 printf("?Ambiguous command\n");
760 continue;
761 }
762 if (c == 0) {
763 printf("?Invalid command\n");
764 continue;
765 }
766 (*c->handler)(margc, margv);
767 }
768}
769
654struct cmd *
770static struct cmd *
655getcmd(char *name)
656{
657 const char *p, *q;
658 struct cmd *c, *found;
659 int nmatches, longest;
660
661 longest = 0;
662 nmatches = 0;

--- 15 unchanged lines hidden (view full) ---

678 return ((struct cmd *)-1);
679 return (found);
680}
681
682/*
683 * Slice a string up into argc/argv.
684 */
685static void
771getcmd(char *name)
772{
773 const char *p, *q;
774 struct cmd *c, *found;
775 int nmatches, longest;
776
777 longest = 0;
778 nmatches = 0;

--- 15 unchanged lines hidden (view full) ---

794 return ((struct cmd *)-1);
795 return (found);
796}
797
798/*
799 * Slice a string up into argc/argv.
800 */
801static void
686makeargv(void)
802makeargv(char *line)
687{
688 char *cp;
689 char **argp = margv;
690
691 margc = 0;
803{
804 char *cp;
805 char **argp = margv;
806
807 margc = 0;
692 if ((cp = strchr(line, '\n')))
808 if ((cp = strchr(line, '\n')) != NULL)
693 *cp = '\0';
809 *cp = '\0';
694 for (cp = line; margc < MAX_MARGV - 1 && *cp;) {
810 for (cp = line; margc < MAX_MARGV - 1 && *cp != '\0';) {
695 while (isspace(*cp))
696 cp++;
697 if (*cp == '\0')
698 break;
699 *argp++ = cp;
700 margc += 1;
701 while (*cp != '\0' && !isspace(*cp))
702 cp++;
703 if (*cp == '\0')
704 break;
705 *cp++ = '\0';
706 }
707 *argp++ = 0;
708}
709
811 while (isspace(*cp))
812 cp++;
813 if (*cp == '\0')
814 break;
815 *argp++ = cp;
816 margc += 1;
817 while (*cp != '\0' && !isspace(*cp))
818 cp++;
819 if (*cp == '\0')
820 break;
821 *cp++ = '\0';
822 }
823 *argp++ = 0;
824}
825
710void
826static void
711quit(int argc __unused, char *argv[] __unused)
712{
827quit(int argc __unused, char *argv[] __unused)
828{
829
713 exit(txrx_error);
714}
715
716/*
717 * Help command.
718 */
830 exit(txrx_error);
831}
832
833/*
834 * Help command.
835 */
719void
836static void
720help(int argc, char *argv[])
721{
722 struct cmd *c;
723
724 if (argc == 1) {
725 printf("Commands may be abbreviated. Commands are:\n\n");
726 for (c = cmdtab; c->name; c++)
727 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
837help(int argc, char *argv[])
838{
839 struct cmd *c;
840
841 if (argc == 1) {
842 printf("Commands may be abbreviated. Commands are:\n\n");
843 for (c = cmdtab; c->name; c++)
844 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
845
846 printf("\n[-] : You shouldn't use these ones anymore.\n");
847 printf("[*] : RFC2834 options support required.\n");
848 printf("[**] : Non-standard RFC2834 option.\n");
728 return;
729 }
730 while (--argc > 0) {
731 char *arg;
732 arg = *++argv;
733 c = getcmd(arg);
734 if (c == (struct cmd *)-1)
849 return;
850 }
851 while (--argc > 0) {
852 char *arg;
853 arg = *++argv;
854 c = getcmd(arg);
855 if (c == (struct cmd *)-1)
735 printf("?Ambiguous help command %s\n", arg);
856 printf("?Ambiguous help command: %s\n", arg);
736 else if (c == (struct cmd *)0)
857 else if (c == (struct cmd *)0)
737 printf("?Invalid help command %s\n", arg);
858 printf("?Invalid help command: %s\n", arg);
738 else
739 printf("%s\n", c->help);
740 }
741}
742
859 else
860 printf("%s\n", c->help);
861 }
862}
863
743void
744settrace(int argc __unused, char **argv __unused)
864static void
865setverbose(int argc __unused, char *argv[] __unused)
745{
866{
746 trace = !trace;
747 printf("Packet tracing %s.\n", trace ? "on" : "off");
748}
749
867
750void
751setverbose(int argc __unused, char **argv __unused)
752{
753 verbose = !verbose;
754 printf("Verbose mode %s.\n", verbose ? "on" : "off");
755}
868 verbose = !verbose;
869 printf("Verbose mode %s.\n", verbose ? "on" : "off");
870}
871
872static void
873setoptions(int argc, char *argv[])
874{
875
876 if (argc == 2) {
877 if (strcasecmp(argv[1], "enable") == 0 ||
878 strcasecmp(argv[1], "on") == 0) {
879 options_extra_enabled = 1;
880 options_rfc_enabled = 1;
881 }
882 if (strcasecmp(argv[1], "disable") == 0 ||
883 strcasecmp(argv[1], "off") == 0) {
884 options_extra_enabled = 0;
885 options_rfc_enabled = 0;
886 }
887 if (strcasecmp(argv[1], "extra") == 0)
888 options_extra_enabled = !options_extra_enabled;
889 }
890 printf("Support for RFC2347 style options are now %s.\n",
891 options_rfc_enabled ? "enabled" : "disabled");
892 printf("Support for non-RFC defined options are now %s.\n",
893 options_extra_enabled ? "enabled" : "disabled");
894
895 printf("\nThe following options are available:\n"
896 "\toptions on : enable support for RFC2347 style options\n"
897 "\toptions off : disable support for RFC2347 style options\n"
898 "\toptions extra : toggle support for non-RFC defined options\n"
899 );
900}
901
902static void
903setrollover(int argc, char *argv[])
904{
905
906 if (argc == 2) {
907 if (strcasecmp(argv[1], "never") == 0 ||
908 strcasecmp(argv[1], "none") == 0) {
909 free(options[OPT_ROLLOVER].o_request);
910 options[OPT_ROLLOVER].o_request = NULL;
911 }
912 if (strcasecmp(argv[1], "1") == 0) {
913 free(options[OPT_ROLLOVER].o_request);
914 options[OPT_ROLLOVER].o_request = strdup("1");
915 }
916 if (strcasecmp(argv[1], "0") == 0) {
917 free(options[OPT_ROLLOVER].o_request);
918 options[OPT_ROLLOVER].o_request = strdup("0");
919 }
920 }
921 printf("Support for the rollover options is %s.\n",
922 options[OPT_ROLLOVER].o_request != NULL ? "enabled" : "disabled");
923 if (options[OPT_ROLLOVER].o_request != NULL)
924 printf("Block rollover will be to block %s.\n",
925 options[OPT_ROLLOVER].o_request);
926
927
928 printf("\nThe following rollover options are available:\n"
929 "\trollover 0 : rollover to block zero (default)\n"
930 "\trollover 1 : rollover to block one\n"
931 "\trollover never : do not support the rollover option\n"
932 "\trollover none : do not support the rollover option\n"
933 );
934}
935
936static void
937setdebug(int argc, char *argv[])
938{
939 int i;
940
941 if (argc != 1) {
942 i = 1;
943 while (i < argc)
944 debug ^= debug_find(argv[i++]);
945 }
946 printf("The following debugging is enabled: %s\n", debug_show(debug));
947
948 printf("\nThe following debugs are available:\n");
949 i = 0;
950 while (debugs[i].name != NULL) {
951 printf("\t%s\t%s\n", debugs[i].name, debugs[i].desc);
952 i++;
953 }
954}
955
956static void
957setblocksize(int argc, char *argv[])
958{
959
960 if (!options_rfc_enabled)
961 printf("RFC2347 style options are not enabled "
962 "(but proceding anyway)\n");
963
964 if (argc != 1) {
965 int size = atoi(argv[1]);
966 size_t max;
967 char maxbuffer[100];
968 int *maxdgram;
969
970 max = sizeof(maxbuffer);
971 if (sysctlbyname("net.inet.udp.maxdgram",
972 maxbuffer, &max, NULL, 0) < 0) {
973 perror("sysctl: net.inet.udp.maxdgram");
974 return;
975 }
976 maxdgram = (int *)maxbuffer;
977
978 if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) {
979 printf("Blocksize should be between %d and %d bytes.\n",
980 BLKSIZE_MIN, BLKSIZE_MAX);
981 return;
982 } else if (size > *maxdgram - 4) {
983 printf("Blocksize can't be bigger than %d bytes due "
984 "to the net.inet.udp.maxdgram sysctl limitation.\n",
985 *maxdgram - 4);
986 asprintf(&options[OPT_BLKSIZE].o_request,
987 "%d", *maxdgram - 4);
988 } else {
989 asprintf(&options[OPT_BLKSIZE].o_request, "%d", size);
990 }
991 }
992 printf("Blocksize is now %s bytes.\n", options[OPT_BLKSIZE].o_request);
993}
994
995static void
996setblocksize2(int argc, char *argv[])
997{
998
999 if (!options_rfc_enabled || !options_extra_enabled)
1000 printf(
1001 "RFC2347 style or non-RFC defined options are not enabled "
1002 "(but proceding anyway)\n");
1003
1004 if (argc != 1) {
1005 int size = atoi(argv[1]);
1006 int i;
1007 size_t max;
1008 char maxbuffer[100];
1009 int *maxdgram;
1010
1011 int sizes[] = {
1012 8, 16, 32, 64, 128, 256, 512, 1024,
1013 2048, 4096, 8192, 16384, 32768, 0
1014 };
1015
1016 max = sizeof(maxbuffer);
1017 if (sysctlbyname("net.inet.udp.maxdgram",
1018 maxbuffer, &max, NULL, 0) < 0) {
1019 perror("sysctl: net.inet.udp.maxdgram");
1020 return;
1021 }
1022 maxdgram = (int *)maxbuffer;
1023
1024 for (i = 0; sizes[i] != 0; i++) {
1025 if (sizes[i] == size) break;
1026 }
1027 if (sizes[i] == 0) {
1028 printf("Blocksize2 should be a power of two between "
1029 "8 and 32768.\n");
1030 return;
1031 }
1032
1033 if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) {
1034 printf("Blocksize2 should be between "
1035 "%d and %d bytes.\n", BLKSIZE_MIN, BLKSIZE_MAX);
1036 return;
1037 } else if (size > *maxdgram - 4) {
1038 printf("Blocksize2 can't be bigger than %d bytes due "
1039 "to the net.inet.udp.maxdgram sysctl limitation.\n",
1040 *maxdgram - 4);
1041 for (i = 0; sizes[i+1] != 0; i++) {
1042 if (*maxdgram < sizes[i+1]) break;
1043 }
1044 asprintf(&options[OPT_BLKSIZE2].o_request,
1045 "%d", sizes[i]);
1046 } else {
1047 asprintf(&options[OPT_BLKSIZE2].o_request, "%d", size);
1048 }
1049 }
1050 printf("Blocksize2 is now %s bytes.\n",
1051 options[OPT_BLKSIZE2].o_request);
1052}
1053
1054static void
1055setpacketdrop(int argc, char *argv[])
1056{
1057
1058 if (argc != 1)
1059 packetdroppercentage = atoi(argv[1]);
1060
1061 printf("Randomly %d in 100 packets will be dropped\n",
1062 packetdroppercentage);
1063}