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 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 *, 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(char *);
105 #define HELPINDENT (sizeof("connect"))
110 void (*handler
)(int, char **);
113 char vhelp
[] = "toggle verbose mode";
114 char thelp
[] = "toggle packet tracing";
115 char chelp
[] = "connect to remote tftp";
116 char qhelp
[] = "exit tftp";
117 char hhelp
[] = "print help information";
118 char shelp
[] = "send file";
119 char rhelp
[] = "receive file";
120 char mhelp
[] = "set file transfer mode";
121 char sthelp
[] = "show current status";
122 char xhelp
[] = "set per-packet retransmission timeout";
123 char ihelp
[] = "set total retransmission timeout";
124 char ashelp
[] = "set mode to netascii";
125 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();
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
, char *port
)
168 struct addrinfo hints
, *res0
, *res
;
170 struct sockaddr_storage ss
;
171 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
, char **argv
)
303 settftpmode("octet");
307 setascii(int argc
, char **argv
)
310 settftpmode("netascii");
314 settftpmode(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], ':')) {
348 for (n
= 1; n
< argc
- 1; n
++)
349 if (strchr(argv
[n
], ':')) {
354 targ
= strrchr(cp
, ':');
356 if (cp
[0] == '[' && cp
[strlen(cp
) - 1] == ']') {
357 cp
[strlen(cp
) - 1] = '\0';
363 printf("No target machine specified.\n");
367 cp
= argc
== 2 ? tail(targ
) : argv
[1];
368 fd
= open(cp
, O_RDONLY
);
374 printf("putting %s to %s:%s [%s]\n",
375 cp
, hostname
, targ
, mode
);
376 xmitfile(fd
, targ
, mode
);
379 /* this assumes the target is a directory */
380 /* on a remote unix system. hmmmm. */
381 cp
= strchr(targ
, '\0');
383 for (n
= 1; n
< argc
- 1; n
++) {
384 strcpy(cp
, tail(argv
[n
]));
385 fd
= open(argv
[n
], O_RDONLY
);
391 printf("putting %s to %s:%s [%s]\n",
392 argv
[n
], hostname
, targ
, mode
);
393 xmitfile(fd
, targ
, mode
);
400 printf("usage: %s file ... host:target, or\n", s
);
401 printf(" %s file ... target (when already connected)\n", s
);
408 get(int argc
, char **argv
)
416 strcpy(line
, "get ");
418 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
428 for (n
= 1; n
< argc
; n
++)
429 if (strrchr(argv
[n
], ':') == 0) {
434 for (n
= 1; n
< argc
; n
++) {
435 src
= strrchr(argv
[n
], ':');
442 if (cp
[0] == '[' && cp
[strlen(cp
) - 1] == ']') {
443 cp
[strlen(cp
) - 1] = '\0';
451 cp
= argc
== 3 ? argv
[2] : tail(src
);
452 fd
= creat(cp
, 0644);
458 printf("getting from %s:%s to %s [%s]\n",
459 hostname
, src
, cp
, mode
);
460 recvfile(fd
, src
, mode
);
463 cp
= tail(src
); /* new .. jdg */
464 fd
= creat(cp
, 0644);
470 printf("getting from %s:%s to %s [%s]\n",
471 hostname
, src
, cp
, mode
);
472 recvfile(fd
, src
, mode
);
479 printf("usage: %s host:file host:file ... file, or\n", s
);
480 printf(" %s file file ... file if connected\n", s
);
483 int rexmtval
= TIMEOUT
;
486 setrexmt(int argc
, char **argv
)
491 strcpy(line
, "Rexmt-timeout ");
493 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
499 printf("usage: %s value\n", argv
[0]);
504 printf("%s: bad value\n", argv
[1]);
509 int maxtimeout
= 5 * TIMEOUT
;
512 settimeout(int argc
, char **argv
)
517 strcpy(line
, "Maximum-timeout ");
519 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
525 printf("usage: %s value\n", argv
[0]);
530 printf("%s: bad value\n", argv
[1]);
536 status(int argc
, char **argv
)
539 printf("Connected to %s.\n", hostname
);
541 printf("Not connected.\n");
542 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
,
543 verbose
? "on" : "off", trace
? "on" : "off");
544 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
545 rexmtval
, maxtimeout
);
552 signal(SIGALRM
, SIG_IGN
);
554 longjmp(toplevel
, -1);
563 s
= strrchr(filename
, '/');
583 printf("%s> ", prompt
);
584 if (fgets(line
, sizeof line
, stdin
) == 0) {
591 if ((cp
= strchr(line
, '\n')))
598 c
= getcmd(margv
[0]);
599 if (c
== (struct cmd
*)-1) {
600 printf("?Ambiguous command\n");
604 printf("?Invalid command\n");
607 (*c
->handler
)(margc
, margv
);
615 struct cmd
*c
, *found
;
616 int nmatches
, longest
;
621 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
622 for (q
= name
; *q
== *p
++; q
++)
623 if (*q
== 0) /* exact match? */
625 if (!*q
) { /* the name was a prefix */
626 if (q
- name
> longest
) {
630 } else if (q
- name
== longest
)
635 return ((struct cmd
*)-1);
640 * Slice a string up into argc/argv.
649 if ((cp
= strchr(line
, '\n')))
651 for (cp
= line
; margc
< MAX_MARGV
-1 && *cp
;) {
658 while (*cp
!= '\0' && !isspace(*cp
))
668 quit(int argc
, char **argv
)
678 help(int argc
, char **argv
)
683 printf("Commands may be abbreviated. Commands are:\n\n");
684 for (c
= cmdtab
; c
->name
; c
++)
685 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
692 if (c
== (struct cmd
*)-1)
693 printf("?Ambiguous help command %s\n", arg
);
694 else if (c
== (struct cmd
*)0)
695 printf("?Invalid help command %s\n", arg
);
697 printf("%s\n", c
->help
);
702 settrace(int argc
, char **argv
)
705 printf("Packet tracing %s.\n", trace
? "on" : "off");
709 setverbose(int argc
, char **argv
)
712 printf("Verbose mode %s.\n", verbose
? "on" : "off");