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";
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
49 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
52 * TFTP User Program -- Command Interface.
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/socket.h>
58 #include <sys/param.h>
60 #include <netinet/in.h>
62 #include <arpa/inet.h>
78 #define TIMEOUT 5 /* secs between rexmt's */
80 struct sockaddr_storage peeraddr;
89 char *margv[MAX_MARGV];
91 volatile int txrx_error;
93 void get(int, char **);
94 void help(int, char **);
96 void modecmd(int, char **);
97 void put(int, char **);
98 void quit(int, char **);
99 void setascii(int, char **);
100 void setbinary(int, char **);
101 void setpeer0(char *, const char *);
102 void setpeer(int, char **);
103 void setrexmt(int, char **);
104 void settimeout(int, char **);
105 void settrace(int, char **);
106 void setverbose(int, char **);
107 void status(int, char **);
109 static void command(void) __dead2;
110 static const char *command_prompt(void);
112 static void getusage(char *);
113 static void makeargv(void);
114 static void putusage(char *);
115 static void settftpmode(const char *);
118 struct cmd *getcmd(char *);
120 #define HELPINDENT (sizeof("connect"))
125 void (*handler)(int, char **);
128 char vhelp[] = "toggle verbose mode";
129 char thelp[] = "toggle packet tracing";
130 char chelp[] = "connect to remote tftp";
131 char qhelp[] = "exit tftp";
132 char hhelp[] = "print help information";
133 char shelp[] = "send file";
134 char rhelp[] = "receive file";
135 char mhelp[] = "set file transfer mode";
136 char sthelp[] = "show current status";
137 char xhelp[] = "set per-packet retransmission timeout";
138 char ihelp[] = "set total retransmission timeout";
139 char ashelp[] = "set mode to netascii";
140 char bnhelp[] = "set mode to octet";
142 struct 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 },
165 strcpy(mode, "netascii");
166 signal(SIGINT, intr);
168 if (setjmp(toplevel) != 0)
172 if (setjmp(toplevel) != 0)
177 char hostname[MAXHOSTNAMELEN];
184 struct addrinfo hints, *res0, *res;
186 struct sockaddr_storage ss;
187 const char *cause = "unknown";
195 memset(&hints, 0, sizeof(hints));
196 hints.ai_family = PF_UNSPEC;
197 hints.ai_socktype = SOCK_DGRAM;
198 hints.ai_protocol = IPPROTO_UDP;
199 hints.ai_flags = AI_CANONNAME;
202 error = getaddrinfo(host, port, &hints, &res0);
204 warnx("%s", gai_strerror(error));
208 for (res = res0; res; res = res->ai_next) {
209 if (res->ai_addrlen > sizeof(peeraddr))
211 f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
217 memset(&ss, 0, sizeof(ss));
218 ss.ss_family = res->ai_family;
219 ss.ss_len = res->ai_addrlen;
220 if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
233 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
234 memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
235 if (res->ai_canonname) {
236 (void) strncpy(hostname, res->ai_canonname,
239 (void) strncpy(hostname, host, sizeof(hostname));
240 hostname[sizeof(hostname)-1] = 0;
254 strcpy(line, "Connect ");
256 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
261 if ((argc < 2) || (argc > 3)) {
262 printf("usage: %s [host [port]]\n", argv[0]);
266 setpeer0(argv[1], argv[2]);
268 setpeer0(argv[1], NULL);
275 { "ascii", "netascii" },
276 { "netascii", "netascii" },
277 { "binary", "octet" },
278 { "image", "octet" },
279 { "octet", "octet" },
280 /* { "mail", "mail" }, */
293 printf("Using %s mode to transfer files.\n", mode);
297 for (p = modes; p->m_name; p++)
298 if (strcmp(argv[1], p->m_name) == 0)
301 settftpmode(p->m_mode);
304 printf("%s: unknown mode\n", argv[1]);
305 /* drop through and print usage message */
308 printf("usage: %s [", argv[0]);
310 for (p = modes; p->m_name; p++) {
311 printf("%s%s", sep, p->m_name);
320 setbinary(argc, argv)
322 char *argv[] __unused;
325 settftpmode("octet");
331 char *argv[] __unused;
334 settftpmode("netascii");
341 strcpy(mode, newmode);
343 printf("mode set to %s\n", mode);
360 strcpy(line, "send ");
362 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
371 targ = argv[argc - 1];
372 if (rindex(argv[argc - 1], ':')) {
375 for (n = 1; n < argc - 1; n++)
376 if (index(argv[n], ':')) {
380 lcp = argv[argc - 1];
381 targ = rindex(lcp, ':');
383 if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
384 lcp[strlen(lcp) - 1] = '\0';
390 printf("No target machine specified.\n");
394 cp = argc == 2 ? tail(targ) : argv[1];
395 fd = open(cp, O_RDONLY);
401 printf("putting %s to %s:%s [%s]\n",
402 cp, hostname, targ, mode);
403 xmitfile(fd, targ, mode);
406 /* this assumes the target is a directory */
407 /* on a remote unix system. hmmmm. */
408 cp = index(targ, '\0');
410 for (n = 1; n < argc - 1; n++) {
411 strcpy(cp, tail(argv[n]));
412 fd = open(argv[n], O_RDONLY);
418 printf("putting %s to %s:%s [%s]\n",
419 argv[n], hostname, targ, mode);
420 xmitfile(fd, targ, mode);
428 printf("usage: %s file [[host:]remotename]\n", s);
429 printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s);
446 strcpy(line, "get ");
448 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
458 for (n = 1; n < argc ; n++)
459 if (rindex(argv[n], ':') == 0) {
464 for (n = 1; n < argc ; n++) {
465 src = rindex(argv[n], ':');
473 if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
474 lcp[strlen(lcp) - 1] = '\0';
482 cp = argc == 3 ? argv[2] : tail(src);
483 fd = creat(cp, 0644);
489 printf("getting from %s:%s to %s [%s]\n",
490 hostname, src, cp, mode);
491 recvfile(fd, src, mode);
494 cp = tail(src); /* new .. jdg */
495 fd = creat(cp, 0644);
501 printf("getting from %s:%s to %s [%s]\n",
502 hostname, src, cp, mode);
503 recvfile(fd, src, mode);
511 printf("usage: %s [host:]file [localname]\n", s);
512 printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
515 int rexmtval = TIMEOUT;
525 strcpy(line, "Rexmt-timeout ");
527 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
533 printf("usage: %s value\n", argv[0]);
538 printf("%s: bad value\n", argv[1]);
543 int maxtimeout = 5 * TIMEOUT;
546 settimeout(argc, argv)
553 strcpy(line, "Maximum-timeout ");
555 fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
561 printf("usage: %s value\n", argv[0]);
566 printf("%s: bad value\n", argv[1]);
574 char *argv[] __unused;
577 printf("Connected to %s.\n", hostname);
579 printf("Not connected.\n");
580 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
581 verbose ? "on" : "off", trace ? "on" : "off");
582 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
583 rexmtval, maxtimeout);
591 signal(SIGALRM, SIG_IGN);
593 longjmp(toplevel, -1);
603 s = rindex(filename, '/');
629 static History *hist;
632 int len, num, vrbose;
636 el = el_init("tftp", stdin, stdout, stderr);
637 hist = history_init();
638 history(hist, &he, H_SETSIZE, 100);
639 el_set(el, EL_HIST, history, hist);
640 el_set(el, EL_EDITOR, "emacs");
641 el_set(el, EL_PROMPT, command_prompt);
642 el_set(el, EL_SIGNAL, 1);
647 if ((bp = el_gets(el, &num)) == NULL || num == 0)
649 len = (num > MAXLINE) ? MAXLINE : num;
650 memcpy(line, bp, len);
652 history(hist, &he, H_ENTER, bp);
654 if (fgets(line, sizeof line , stdin) == 0) {
662 if ((cp = strchr(line, '\n')))
669 c = getcmd(margv[0]);
670 if (c == (struct cmd *)-1) {
671 printf("?Ambiguous command\n");
675 printf("?Invalid command\n");
678 (*c->handler)(margc, margv);
687 struct cmd *c, *found;
688 int nmatches, longest;
693 for (c = cmdtab; (p = c->name) != NULL; c++) {
694 for (q = name; *q == *p++; q++)
695 if (*q == 0) /* exact match? */
697 if (!*q) { /* the name was a prefix */
698 if (q - name > longest) {
702 } else if (q - name == longest)
707 return ((struct cmd *)-1);
712 * Slice a string up into argc/argv.
721 if ((cp = strchr(line, '\n')))
723 for (cp = line; margc < MAX_MARGV - 1 && *cp;) {
730 while (*cp != '\0' && !isspace(*cp))
742 char *argv[] __unused;
758 printf("Commands may be abbreviated. Commands are:\n\n");
759 for (c = cmdtab; c->name; c++)
760 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
767 if (c == (struct cmd *)-1)
768 printf("?Ambiguous help command %s\n", arg);
769 else if (c == (struct cmd *)0)
770 printf("?Invalid help command %s\n", arg);
772 printf("%s\n", c->help);
779 char **argv __unused;
782 printf("Packet tracing %s.\n", trace ? "on" : "off");
786 setverbose(argc, argv)
788 char **argv __unused;
791 printf("Verbose mode %s.\n", verbose ? "on" : "off");