1 /* $NetBSD: main.c,v 1.19 2003/10/02 23:31:52 itojun Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 __attribute__((__used__
))
34 static const char copyright
[] =
35 "@(#) Copyright (c) 1983, 1993\n\
36 The Regents of the University of California. All rights reserved.\n";
41 static char sccsid
[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD: src/usr.bin/tftp/main.c,v 1.22 2005/10/19 15:37:42 stefanf 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>
62 #include <arpa/tftp.h>
79 #define TIMEOUT 5 /* secs between rexmt's */
80 #define MAXSEGSIZE 65464
81 struct sockaddr_storage peeraddr
;
87 int def_blksize
=SEGSIZE
;
94 char *margv
[MAX_MARGV
];
96 volatile int txrx_error
;
98 void get(int, char **);
99 void help(int, char **);
101 void modecmd(int, char **);
102 void put(int, char **);
103 void quit(int, char **);
104 void setascii(int, char **);
105 void setbinary(int, char **);
106 void setpeer0(char *, const char *);
107 void setpeer(int, char **);
108 void setrexmt(int, char **);
109 void settimeout(int, char **);
110 void settrace(int, char **);
111 void setverbose(int, char **);
113 void setblksize(int, char **);
114 void settsize(int, char **);
115 void settimeoutopt(int, char **);
117 void status(int, char **);
120 int main(int, char *[]);
122 struct cmd
*getcmd(char *);
125 static void command(void) __dead2
;
126 static const char *command_prompt(void);
128 static void getusage(char *);
129 static void makeargv(void);
130 static void putusage(char *);
131 static void settftpmode(const char *);
134 struct cmd
*getcmd(char *);
136 #define HELPINDENT (sizeof("connect"))
141 void (*handler
)(int, char **);
144 char vhelp
[] = "toggle verbose mode";
145 char thelp
[] = "toggle packet tracing";
147 char tshelp
[] = "toggle extended tsize option";
148 char tohelp
[] = "toggle extended timeout option";
149 char blhelp
[] = "set an alternative blocksize (def. 512)";
151 char chelp
[] = "connect to remote tftp";
152 char qhelp
[] = "exit tftp";
153 char hhelp
[] = "print help information";
154 char shelp
[] = "send file";
155 char rhelp
[] = "receive file";
156 char mhelp
[] = "set file transfer mode";
157 char sthelp
[] = "show current status";
158 char xhelp
[] = "set per-packet retransmission timeout";
159 char ihelp
[] = "set total retransmission timeout";
160 char ashelp
[] = "set mode to netascii";
161 char bnhelp
[] = "set mode to octet";
163 struct cmd cmdtab
[] = {
164 { "connect", chelp
, setpeer
},
165 { "mode", mhelp
, modecmd
},
166 { "put", shelp
, put
},
167 { "get", rhelp
, get
},
168 { "quit", qhelp
, quit
},
169 { "verbose", vhelp
, setverbose
},
171 { "blksize", blhelp
, setblksize
},
172 { "tsize", tshelp
, settsize
},
174 { "trace", thelp
, settrace
},
175 { "status", sthelp
, status
},
176 { "binary", bnhelp
, setbinary
},
177 { "ascii", ashelp
, setascii
},
178 { "rexmt", xhelp
, setrexmt
},
179 { "timeout", ihelp
, settimeout
},
181 { "tout", tohelp
, settimeoutopt
},
183 { "?", hhelp
, help
},
195 strcpy(mode
, "netascii");
196 signal(SIGINT
, intr
);
198 setprogname(argv
[0]);
199 while ((c
= getopt(argc
, argv
, "e")) != -1) {
202 blksize
= MAXSEGSIZE
;
203 strcpy(mode
, "octet");
208 printf("usage: %s [-e] host-name [port]\n",
217 if (setjmp(toplevel
) != 0)
223 if (setjmp(toplevel
) != 0)
229 char hostname
[MAXHOSTNAMELEN
];
236 struct addrinfo hints
, *res0
, *res
;
238 struct sockaddr_storage ss
;
239 const char *cause
= "unknown";
247 memset(&hints
, 0, sizeof(hints
));
248 hints
.ai_family
= PF_UNSPEC
;
249 hints
.ai_socktype
= SOCK_DGRAM
;
250 hints
.ai_protocol
= IPPROTO_UDP
;
251 hints
.ai_flags
= AI_CANONNAME
;
254 error
= getaddrinfo(host
, port
, &hints
, &res0
);
256 warnx("%s", gai_strerror(error
));
260 for (res
= res0
; res
; res
= res
->ai_next
) {
261 if (res
->ai_addrlen
> sizeof(peeraddr
))
263 f
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
269 memset(&ss
, 0, sizeof(ss
));
270 ss
.ss_family
= res
->ai_family
;
271 ss
.ss_len
= res
->ai_addrlen
;
272 if (bind(f
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0) {
284 if (setsockopt(f
, SOL_SOCKET
, SO_SNDBUF
, &soopt
, sizeof(soopt
))
288 cause
= "setsockopt SNDBUF";
290 if (setsockopt(f
, SOL_SOCKET
, SO_RCVBUF
, &soopt
, sizeof(soopt
))
294 cause
= "setsockopt RCVBUF";
301 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
302 memcpy(&peeraddr
, res
->ai_addr
, res
->ai_addrlen
);
303 if (res
->ai_canonname
) {
304 (void) strlcpy(hostname
, res
->ai_canonname
,
307 (void) strlcpy(hostname
, host
, sizeof(hostname
));
321 strcpy(line
, "Connect ");
323 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
328 if ((argc
< 2) || (argc
> 3)) {
329 printf("usage: %s [-e] host-name [port]\n", getprogname());
333 setpeer0(argv
[1], argv
[2]);
335 setpeer0(argv
[1], NULL
);
342 { "ascii", "netascii" },
343 { "netascii", "netascii" },
344 { "binary", "octet" },
345 { "image", "octet" },
346 { "octet", "octet" },
347 /* { "mail", "mail" }, */
360 printf("Using %s mode to transfer files.\n", mode
);
364 for (p
= modes
; p
->m_name
; p
++)
365 if (strcmp(argv
[1], p
->m_name
) == 0)
368 settftpmode(p
->m_mode
);
371 printf("%s: unknown mode\n", argv
[1]);
372 /* drop through and print usage message */
375 printf("usage: %s [", argv
[0]);
377 for (p
= modes
; p
->m_name
; p
++) {
378 printf("%s%s", sep
, p
->m_name
);
387 setbinary(argc
, argv
)
389 char *argv
[] __unused
;
392 settftpmode("octet");
398 char *argv
[] __unused
;
401 settftpmode("netascii");
408 strcpy(mode
, newmode
);
410 printf("mode set to %s\n", mode
);
426 char targbuf
[PATH_MAX
];
427 #endif /* __APPLE__ */
430 strcpy(line
, "send ");
432 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
441 targ
= argv
[argc
- 1];
442 if (rindex(argv
[argc
- 1], ':')) {
445 for (n
= 1; n
< argc
- 1; n
++)
446 if (index(argv
[n
], ':')) {
450 lcp
= argv
[argc
- 1];
451 targ
= rindex(lcp
, ':');
453 if (lcp
[0] == '[' && lcp
[strlen(lcp
) - 1] == ']') {
454 lcp
[strlen(lcp
) - 1] = '\0';
460 printf("No target machine specified.\n");
464 cp
= argc
== 2 ? tail(targ
) : argv
[1];
465 fd
= open(cp
, O_RDONLY
);
471 printf("putting %s to %s:%s [%s]\n",
472 cp
, hostname
, targ
, mode
);
473 xmitfile(fd
, targ
, mode
);
476 /* this assumes the target is a directory */
477 /* on a remote unix system. hmmmm. */
479 snprintf(targbuf
, sizeof(targbuf
), "%s/", targ
);
480 cp
= targbuf
+ strlen(targbuf
);
481 #else /* !__APPLE__ */
482 cp
= index(targ
, '\0');
484 #endif /* __APPLE__ */
485 for (n
= 1; n
< argc
- 1; n
++) {
487 strlcpy(cp
, tail(argv
[n
]), sizeof(targbuf
) - (cp
- targbuf
));
488 #else /* !__APPLE__ */
489 strcpy(cp
, tail(argv
[n
]));
490 #endif /* __APPLE__ */
491 fd
= open(argv
[n
], O_RDONLY
);
497 printf("putting %s to %s:%s [%s]\n",
499 argv
[n
], hostname
, targbuf
, mode
);
500 #else /* !__APPLE__ */
501 argv
[n
], hostname
, targ
, mode
);
502 #endif /* __APPLE__ */
503 xmitfile(fd
, targ
, mode
);
511 printf("usage: %s file ... host:target, or\n", s
);
512 printf(" %s file ... target (when already connected)\n", s
);
529 strcpy(line
, "get ");
531 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
541 for (n
= 1; n
< argc
; n
++)
542 if (rindex(argv
[n
], ':') == 0) {
547 for (n
= 1; n
< argc
; n
++) {
548 src
= rindex(argv
[n
], ':');
556 if (lcp
[0] == '[' && lcp
[strlen(lcp
) - 1] == ']') {
557 lcp
[strlen(lcp
) - 1] = '\0';
565 cp
= argc
== 3 ? argv
[2] : tail(src
);
566 fd
= creat(cp
, 0644);
572 printf("getting from %s:%s to %s [%s]\n",
573 hostname
, src
, cp
, mode
);
574 recvfile(fd
, src
, mode
);
577 cp
= tail(src
); /* new .. jdg */
578 fd
= creat(cp
, 0644);
584 printf("getting from %s:%s to %s [%s]\n",
585 hostname
, src
, cp
, mode
);
586 recvfile(fd
, src
, mode
);
594 printf("usage: %s host:file host:file ... file, or\n", s
);
595 printf(" %s file file ... file if connected\n", s
);
599 setblksize(argc
, argv
)
606 strcpy(line
, "blksize ");
607 printf("(blksize) ");
608 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
614 printf("usage: %s value\n", argv
[0]);
618 if (t
< 8 || t
> 65464)
619 printf("%s: bad value\n", argv
[1]);
624 int def_rexmtval
= TIMEOUT
;
625 int rexmtval
= TIMEOUT
;
635 strcpy(line
, "Rexmt-timeout ");
637 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
643 printf("usage: %s value\n", argv
[0]);
648 printf("%s: bad value\n", argv
[1]);
653 int maxtimeout
= 5 * TIMEOUT
;
656 settimeout(argc
, argv
)
663 strcpy(line
, "Maximum-timeout ");
665 fgets(&line
[strlen(line
)], sizeof line
- strlen(line
), stdin
);
671 printf("usage: %s value\n", argv
[0]);
676 printf("%s: bad value\n", argv
[1]);
684 char *argv
[] __unused
;
687 printf("Connected to %s.\n", hostname
);
689 printf("Not connected.\n");
690 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
,
691 verbose
? "on" : "off", trace
? "on" : "off");
692 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
693 rexmtval
, maxtimeout
);
701 signal(SIGALRM
, SIG_IGN
);
703 longjmp(toplevel
, -1);
713 s
= rindex(filename
, '/');
739 static History
*hist
;
742 int len
, num
, vrbose
;
746 el
= el_init("tftp", stdin
, stdout
, stderr
);
747 hist
= history_init();
748 history(hist
, &he
, H_SETSIZE
, 100);
749 el_set(el
, EL_HIST
, history
, hist
);
750 el_set(el
, EL_EDITOR
, "emacs");
751 el_set(el
, EL_PROMPT
, command_prompt
);
752 el_set(el
, EL_SIGNAL
, 1);
757 if ((bp
= el_gets(el
, &num
)) == NULL
|| num
== 0)
759 len
= (num
> MAXLINE
) ? MAXLINE
: num
;
760 memcpy(line
, bp
, len
);
762 history(hist
, &he
, H_ENTER
, bp
);
764 if (fgets(line
, sizeof line
, stdin
) == 0) {
772 if ((cp
= strchr(line
, '\n')))
779 c
= getcmd(margv
[0]);
780 if (c
== (struct cmd
*)-1) {
781 printf("?Ambiguous command\n");
785 printf("?Invalid command\n");
788 (*c
->handler
)(margc
, margv
);
797 struct cmd
*c
, *found
;
798 int nmatches
, longest
;
803 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
804 for (q
= name
; *q
== *p
++; q
++)
805 if (*q
== 0) /* exact match? */
807 if (!*q
) { /* the name was a prefix */
808 if (q
- name
> longest
) {
812 } else if (q
- name
== longest
)
817 return ((struct cmd
*)-1);
822 * Slice a string up into argc/argv.
831 if ((cp
= strchr(line
, '\n')))
833 for (cp
= line
; margc
< MAX_MARGV
- 1 && *cp
;) {
834 while (isspace((unsigned char)*cp
))
840 while (*cp
!= '\0' && !isspace((unsigned char)*cp
))
852 char *argv
[] __unused
;
868 printf("Commands may be abbreviated. Commands are:\n\n");
869 for (c
= cmdtab
; c
->name
; c
++)
870 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
877 if (c
== (struct cmd
*)-1)
878 printf("?Ambiguous help command %s\n", arg
);
879 else if (c
== (struct cmd
*)0)
880 printf("?Invalid help command %s\n", arg
);
882 printf("%s\n", c
->help
);
889 char **argv __unused
;
892 printf("Packet tracing %s.\n", trace
? "on" : "off");
896 setverbose(argc
, argv
)
898 char **argv __unused
;
901 printf("Verbose mode %s.\n", verbose
? "on" : "off");
907 char **argv __unused
;
910 printf("Tsize mode %s.\n", tsize
? "on" : "off");
914 settimeoutopt(argc
, argv
)
916 char **argv __unused
;
919 printf("Timeout option %s.\n", tout
? "on" : "off");