2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
42 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
44 static const char rcsid[] =
45 "$FreeBSD: src/usr.bin/tftp/main.c,v 1.8.2.3 2002/05/14 22:08:07 bsd Exp $";
48 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
51 * TFTP User Program -- Command Interface.
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
57 #include <sys/param.h>
59 #include <netinet/in.h>
61 #include <arpa/inet.h>
75 #define TIMEOUT 5 /* secs between rexmt's */
77 struct sockaddr_storage peeraddr;
86 char *prompt = "tftp";
88 volatile int txrx_error;
91 void get __P((int, char **));
92 void help __P((int, char **));
93 void modecmd __P((int, char **));
94 void put __P((int, char **));
95 void quit __P((int, char **));
96 void setascii __P((int, char **));
97 void setbinary __P((int, char **));
98 void setpeer0 __P((char *, char *));
99 void setpeer __P((int, char **));
100 void setrexmt __P((int, char **));
101 void settimeout __P((int, char **));
102 void settrace __P((int, char **));
103 void setverbose __P((int, char **));
104 void status __P((int, char **));
106 static void command __P((void)) __dead2;
108 static void getusage __P((char *));
109 static void makeargv __P((void));
110 static void putusage __P((char *));
111 static void settftpmode __P((char *));
113 #define HELPINDENT (sizeof("connect"))
118 void (*handler) __P((int, char **));
121 char vhelp[] = "toggle verbose mode";
122 char thelp[] = "toggle packet tracing";
123 char chelp[] = "connect to remote tftp";
124 char qhelp[] = "exit tftp";
125 char hhelp[] = "print help information";
126 char shelp[] = "send file";
127 char rhelp[] = "receive file";
128 char mhelp[] = "set file transfer mode";
129 char sthelp[] = "show current status";
130 char xhelp[] = "set per-packet retransmission timeout";
131 char ihelp[] = "set total retransmission timeout";
132 char ashelp[] = "set mode to netascii";
133 char bnhelp[] = "set mode to octet";
135 struct cmd cmdtab[] = {
136 { "connect", chelp, setpeer },
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 { "?", hhelp, help },
152 struct cmd *getcmd();
161 strcpy(mode, "netascii");
162 signal(SIGINT, intr);
164 if (setjmp(toplevel) != 0)
168 if (setjmp(toplevel) != 0)
173 char hostname[MAXHOSTNAMELEN];
180 struct addrinfo hints, *res0, *res;
182 struct sockaddr_storage ss;
183 char *cause = "unknown";
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;
198 error = getaddrinfo(host, port, &hints, &res0);
200 warnx("%s", gai_strerror(error));
204 for (res = res0; res; res = res->ai_next) {
205 if (res->ai_addrlen > sizeof(peeraddr))
207 f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
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) {
229 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
230 memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
231 if (res->ai_canonname) {
232 (void) strncpy(hostname, res->ai_canonname,
235 (void) strncpy(hostname, host, sizeof(hostname));
236 hostname[sizeof(hostname)-1] = 0;
250 strcpy(line, "Connect ");
252 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
257 if ((argc < 2) || (argc > 3)) {
258 printf("usage: %s host-name [port]\n", argv[0]);
262 setpeer0(argv[1], NULL);
264 setpeer0(argv[1], argv[2]);
271 { "ascii", "netascii" },
272 { "netascii", "netascii" },
273 { "binary", "octet" },
274 { "image", "octet" },
275 { "octet", "octet" },
276 /* { "mail", "mail" }, */
285 register struct modes *p;
289 printf("Using %s mode to transfer files.\n", mode);
293 for (p = modes; p->m_name; p++)
294 if (strcmp(argv[1], p->m_name) == 0)
297 settftpmode(p->m_mode);
300 printf("%s: unknown mode\n", argv[1]);
301 /* drop through and print usage message */
304 printf("usage: %s [", argv[0]);
306 for (p = modes; p->m_name; p++) {
307 printf("%s%s", sep, p->m_name);
316 setbinary(argc, argv)
321 settftpmode("octet");
330 settftpmode("netascii");
337 strcpy(mode, newmode);
339 printf("mode set to %s\n", mode);
353 register char *cp, *targ;
356 strcpy(line, "send ");
358 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
367 targ = argv[argc - 1];
368 if (rindex(argv[argc - 1], ':')) {
371 for (n = 1; n < argc - 1; n++)
372 if (index(argv[n], ':')) {
377 targ = rindex(cp, ':');
379 if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
380 cp[strlen(cp) - 1] = '\0';
386 printf("No target machine specified.\n");
390 cp = argc == 2 ? tail(targ) : argv[1];
391 fd = open(cp, O_RDONLY);
397 printf("putting %s to %s:%s [%s]\n",
398 cp, hostname, targ, mode);
399 xmitfile(fd, targ, mode);
402 /* this assumes the target is a directory */
403 /* on a remote unix system. hmmmm. */
404 cp = index(targ, '\0');
406 for (n = 1; n < argc - 1; n++) {
407 strcpy(cp, tail(argv[n]));
408 fd = open(argv[n], O_RDONLY);
414 printf("putting %s to %s:%s [%s]\n",
415 argv[n], hostname, targ, mode);
416 xmitfile(fd, targ, mode);
424 printf("usage: %s file ... host:target, or\n", s);
425 printf(" %s file ... target (when already connected)\n", s);
442 strcpy(line, "get ");
444 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
454 for (n = 1; n < argc ; n++)
455 if (rindex(argv[n], ':') == 0) {
460 for (n = 1; n < argc ; n++) {
461 src = rindex(argv[n], ':');
468 if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
469 cp[strlen(cp) - 1] = '\0';
477 cp = argc == 3 ? argv[2] : tail(src);
478 fd = creat(cp, 0644);
484 printf("getting from %s:%s to %s [%s]\n",
485 hostname, src, cp, mode);
486 recvfile(fd, src, mode);
489 cp = tail(src); /* new .. jdg */
490 fd = creat(cp, 0644);
496 printf("getting from %s:%s to %s [%s]\n",
497 hostname, src, cp, mode);
498 recvfile(fd, src, mode);
506 printf("usage: %s host:file host:file ... file, or\n", s);
507 printf(" %s file file ... file if connected\n", s);
510 int rexmtval = TIMEOUT;
520 strcpy(line, "Rexmt-timeout ");
522 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
528 printf("usage: %s value\n", argv[0]);
533 printf("%s: bad value\n", argv[1]);
538 int maxtimeout = 5 * TIMEOUT;
541 settimeout(argc, argv)
548 strcpy(line, "Maximum-timeout ");
550 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
556 printf("usage: %s value\n", argv[0]);
561 printf("%s: bad value\n", argv[1]);
572 printf("Connected to %s.\n", hostname);
574 printf("Not connected.\n");
575 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
576 verbose ? "on" : "off", trace ? "on" : "off");
577 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
578 rexmtval, maxtimeout);
585 signal(SIGALRM, SIG_IGN);
587 longjmp(toplevel, -1);
597 s = rindex(filename, '/');
613 register struct cmd *c;
617 printf("%s> ", prompt);
618 if (fgets(line, sizeof line , stdin) == 0) {
625 if ((cp = strchr(line, '\n')))
632 c = getcmd(margv[0]);
633 if (c == (struct cmd *)-1) {
634 printf("?Ambiguous command\n");
638 printf("?Invalid command\n");
641 (*c->handler)(margc, margv);
649 register char *p, *q;
650 register struct cmd *c, *found;
651 register int nmatches, longest;
656 for (c = cmdtab; (p = c->name) != NULL; c++) {
657 for (q = name; *q == *p++; q++)
658 if (*q == 0) /* exact match? */
660 if (!*q) { /* the name was a prefix */
661 if (q - name > longest) {
665 } else if (q - name == longest)
670 return ((struct cmd *)-1);
675 * Slice a string up into argc/argv.
681 register char **argp = margv;
684 if ((cp = strchr(line, '\n')))
686 for (cp = line; *cp;) {
693 while (*cp != '\0' && !isspace(*cp))
719 register struct cmd *c;
722 printf("Commands may be abbreviated. Commands are:\n\n");
723 for (c = cmdtab; c->name; c++)
724 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
731 if (c == (struct cmd *)-1)
732 printf("?Ambiguous help command %s\n", arg);
733 else if (c == (struct cmd *)0)
734 printf("?Invalid help command %s\n", arg);
736 printf("%s\n", c->help);
746 printf("Packet tracing %s.\n", trace ? "on" : "off");
750 setverbose(argc, argv)
755 printf("Verbose mode %s.\n", verbose ? "on" : "off");