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
33 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)main.c 8.1 (Berkeley) 6/6/93
35 * $FreeBSD: src/usr.bin/tftp/main.c,v 1.8.2.3 2002/05/14 22:08:07 bsd Exp $
36 * $DragonFly: src/usr.bin/tftp/main.c,v 1.6 2008/10/16 01:52:33 swildner Exp $
39 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
42 * TFTP User Program -- Command Interface.
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
48 #include <sys/param.h>
50 #include <netinet/in.h>
52 #include <arpa/inet.h>
66 #define TIMEOUT 5 /* secs between rexmt's */
68 struct sockaddr_storage peeraddr;
77 char *margv[MAX_MARGV];
78 const char *prompt = "tftp";
80 volatile int txrx_error;
83 void get(int, char **);
84 void help(int, char **);
85 void modecmd(int, char **);
86 void put(int, char **);
87 void quit(int, char **);
88 void setascii(int, char **);
89 void setbinary(int, char **);
90 void setpeer0(char *, const char *);
91 void setpeer(int, char **);
92 void setrexmt(int, char **);
93 void settimeout(int, char **);
94 void settrace(int, char **);
95 void setverbose(int, char **);
96 void status(int, char **);
98 static void command(void) __dead2;
100 static void getusage(char *);
101 static void makeargv(void);
102 static void putusage(char *);
103 static void settftpmode(const char *);
105 #define HELPINDENT (sizeof("connect"))
110 void (*handler)(int, char **);
113 const char vhelp[] = "toggle verbose mode";
114 const char thelp[] = "toggle packet tracing";
115 const char chelp[] = "connect to remote tftp";
116 const char qhelp[] = "exit tftp";
117 const char hhelp[] = "print help information";
118 const char shelp[] = "send file";
119 const char rhelp[] = "receive file";
120 const char mhelp[] = "set file transfer mode";
121 const char sthelp[] = "show current status";
122 const char xhelp[] = "set per-packet retransmission timeout";
123 const char ihelp[] = "set total retransmission timeout";
124 const char ashelp[] = "set mode to netascii";
125 const char bnhelp[] = "set mode to octet";
127 struct cmd cmdtab[] = {
128 { "connect", chelp, setpeer },
129 { "mode", mhelp, modecmd },
130 { "put", shelp, put },
131 { "get", rhelp, get },
132 { "quit", qhelp, quit },
133 { "verbose", vhelp, setverbose },
134 { "trace", thelp, settrace },
135 { "status", sthelp, status },
136 { "binary", bnhelp, setbinary },
137 { "ascii", ashelp, setascii },
138 { "rexmt", xhelp, setrexmt },
139 { "timeout", ihelp, settimeout },
140 { "?", hhelp, help },
144 struct cmd *getcmd(char *);
148 main(int argc, char **argv)
151 strcpy(mode, "netascii");
152 signal(SIGINT, intr);
154 if (setjmp(toplevel) != 0)
158 if (setjmp(toplevel) != 0)
163 char hostname[MAXHOSTNAMELEN];
166 setpeer0(char *host, const char *port)
168 struct addrinfo hints, *res0, *res;
170 struct sockaddr_storage ss;
171 const char *cause = "unknown";
179 memset(&hints, 0, sizeof(hints));
180 hints.ai_family = PF_UNSPEC;
181 hints.ai_socktype = SOCK_DGRAM;
182 hints.ai_protocol = IPPROTO_UDP;
183 hints.ai_flags = AI_CANONNAME;
186 error = getaddrinfo(host, port, &hints, &res0);
188 warnx("%s", gai_strerror(error));
192 for (res = res0; res; res = res->ai_next) {
193 if (res->ai_addrlen > sizeof(peeraddr))
195 f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
201 memset(&ss, 0, sizeof(ss));
202 ss.ss_family = res->ai_family;
203 ss.ss_len = res->ai_addrlen;
204 if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
217 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
218 memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
219 if (res->ai_canonname) {
220 (void) strncpy(hostname, res->ai_canonname,
223 (void) strncpy(hostname, host, sizeof(hostname));
224 hostname[sizeof(hostname)-1] = 0;
232 setpeer(int argc, char **argv)
236 strcpy(line, "Connect ");
238 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
243 if ((argc < 2) || (argc > 3)) {
244 printf("usage: %s host-name [port]\n", argv[0]);
248 setpeer0(argv[1], NULL);
250 setpeer0(argv[1], argv[2]);
257 { "ascii", "netascii" },
258 { "netascii", "netascii" },
259 { "binary", "octet" },
260 { "image", "octet" },
261 { "octet", "octet" },
262 /* { "mail", "mail" }, */
267 modecmd(int argc, char **argv)
273 printf("Using %s mode to transfer files.\n", mode);
277 for (p = modes; p->m_name; p++)
278 if (strcmp(argv[1], p->m_name) == 0)
281 settftpmode(p->m_mode);
284 printf("%s: unknown mode\n", argv[1]);
285 /* drop through and print usage message */
288 printf("usage: %s [", argv[0]);
290 for (p = modes; p->m_name; p++) {
291 printf("%s%s", sep, p->m_name);
300 setbinary(int argc __unused, char **argv __unused)
303 settftpmode("octet");
307 setascii(int argc __unused, char **argv __unused)
310 settftpmode("netascii");
314 settftpmode(const char *newmode)
316 strcpy(mode, newmode);
318 printf("mode set to %s\n", mode);
326 put(int argc, char **argv)
333 strcpy(line, "send ");
335 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
344 targ = argv[argc - 1];
345 if (strrchr(argv[argc - 1], ':')) {
346 for (n = 1; n < argc - 1; n++)
347 if (strchr(argv[n], ':')) {
352 targ = strrchr(cp, ':');
354 if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
355 cp[strlen(cp) - 1] = '\0';
361 printf("No target machine specified.\n");
365 cp = argc == 2 ? tail(targ) : argv[1];
366 fd = open(cp, O_RDONLY);
372 printf("putting %s to %s:%s [%s]\n",
373 cp, hostname, targ, mode);
374 xmitfile(fd, targ, mode);
377 /* this assumes the target is a directory */
378 /* on a remote unix system. hmmmm. */
379 cp = strchr(targ, '\0');
381 for (n = 1; n < argc - 1; n++) {
382 strcpy(cp, tail(argv[n]));
383 fd = open(argv[n], O_RDONLY);
389 printf("putting %s to %s:%s [%s]\n",
390 argv[n], hostname, targ, mode);
391 xmitfile(fd, targ, mode);
398 printf("usage: %s file ... host:target, or\n", s);
399 printf(" %s file ... target (when already connected)\n", s);
406 get(int argc, char **argv)
414 strcpy(line, "get ");
416 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
426 for (n = 1; n < argc ; n++)
427 if (strrchr(argv[n], ':') == 0) {
432 for (n = 1; n < argc ; n++) {
433 src = strrchr(argv[n], ':');
439 if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
440 cp[strlen(cp) - 1] = '\0';
448 cp = argc == 3 ? argv[2] : tail(src);
449 fd = creat(cp, 0644);
455 printf("getting from %s:%s to %s [%s]\n",
456 hostname, src, cp, mode);
457 recvfile(fd, src, mode);
460 cp = tail(src); /* new .. jdg */
461 fd = creat(cp, 0644);
467 printf("getting from %s:%s to %s [%s]\n",
468 hostname, src, cp, mode);
469 recvfile(fd, src, mode);
476 printf("usage: %s host:file host:file ... file, or\n", s);
477 printf(" %s file file ... file if connected\n", s);
480 int rexmtval = TIMEOUT;
483 setrexmt(int argc, char **argv)
488 strcpy(line, "Rexmt-timeout ");
490 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
496 printf("usage: %s value\n", argv[0]);
501 printf("%s: bad value\n", argv[1]);
506 int maxtimeout = 5 * TIMEOUT;
509 settimeout(int argc, char **argv)
514 strcpy(line, "Maximum-timeout ");
516 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
522 printf("usage: %s value\n", argv[0]);
527 printf("%s: bad value\n", argv[1]);
533 status(int argc __unused, char **argv __unused)
536 printf("Connected to %s.\n", hostname);
538 printf("Not connected.\n");
539 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
540 verbose ? "on" : "off", trace ? "on" : "off");
541 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
542 rexmtval, maxtimeout);
546 intr(int signo __unused)
548 signal(SIGALRM, SIG_IGN);
550 longjmp(toplevel, -1);
559 s = strrchr(filename, '/');
579 printf("%s> ", prompt);
580 if (fgets(line, sizeof line , stdin) == 0) {
587 if ((cp = strchr(line, '\n')))
594 c = getcmd(margv[0]);
595 if (c == (struct cmd *)-1) {
596 printf("?Ambiguous command\n");
600 printf("?Invalid command\n");
603 (*c->handler)(margc, margv);
612 struct cmd *c, *found;
613 int nmatches, longest;
618 for (c = cmdtab; (p = c->name) != NULL; c++) {
619 for (q = name; *q == *p++; q++)
620 if (*q == 0) /* exact match? */
622 if (!*q) { /* the name was a prefix */
623 if (q - name > longest) {
627 } else if (q - name == longest)
632 return ((struct cmd *)-1);
637 * Slice a string up into argc/argv.
646 if ((cp = strchr(line, '\n')))
648 for (cp = line; margc < MAX_MARGV -1 && *cp;) {
655 while (*cp != '\0' && !isspace(*cp))
665 quit(int argc __unused, char **argv __unused)
675 help(int argc, char **argv)
680 printf("Commands may be abbreviated. Commands are:\n\n");
681 for (c = cmdtab; c->name; c++)
682 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
689 if (c == (struct cmd *)-1)
690 printf("?Ambiguous help command %s\n", arg);
692 printf("?Invalid help command %s\n", arg);
694 printf("%s\n", c->help);
699 settrace(int argc __unused, char **argv __unused)
702 printf("Packet tracing %s.\n", trace ? "on" : "off");
706 setverbose(int argc __unused, char **argv __unused)
709 printf("Verbose mode %s.\n", verbose ? "on" : "off");