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
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
37 static char sccsid
[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
39 __RCSID("$NetBSD: main.c,v 1.19 2003/10/02 23:31:52 itojun Exp $");
43 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
46 * TFTP User Program -- Command Interface.
48 #include <sys/types.h>
49 #include <sys/socket.h>
51 #include <netinet/in.h>
53 #include <arpa/inet.h>
70 #define TIMEOUT 5 /* secs between rexmt's */
71 #define LBUFLEN 200 /* size of input buffer */
72 #define MAXSEGSIZE 65464
73 struct sockaddr_storage peeraddr
;
79 int def_blksize
=SEGSIZE
;
86 char *prompt
= "tftp";
89 void get
__P((int, char **));
90 void help
__P((int, char **));
91 void modecmd
__P((int, char **));
92 void put
__P((int, char **));
93 void quit
__P((int, char **));
94 void setascii
__P((int, char **));
95 void setbinary
__P((int, char **));
96 void setpeer0
__P((char *, char *));
97 void setpeer
__P((int, char **));
98 void setrexmt
__P((int, char **));
99 void settimeout
__P((int, char **));
100 void settrace
__P((int, char **));
101 void setverbose
__P((int, char **));
102 void setblksize
__P((int, char **));
103 void settsize
__P((int, char **));
104 void settimeoutopt
__P((int, char **));
105 void status
__P((int, char **));
106 char *tail
__P((char *));
107 int main
__P((int, char *[]));
108 void intr
__P((int));
109 struct cmd
*getcmd
__P((char *));
111 static __dead
void command
__P((void));
113 static void getusage
__P((char *));
114 static void makeargv
__P((void));
115 static void putusage
__P((char *));
116 static void settftpmode
__P((char *));
118 #define HELPINDENT (sizeof("connect"))
123 void (*handler
) __P((int, char **));
126 char vhelp
[] = "toggle verbose mode";
127 char thelp
[] = "toggle packet tracing";
128 char tshelp
[] = "toggle extended tsize option";
129 char tohelp
[] = "toggle extended timeout option";
130 char blhelp
[] = "set an alternative blocksize (def. 512)";
131 char chelp
[] = "connect to remote tftp";
132 char qhelp
[] = "exit tftp";
133 char hhelp
[] = "print help information";
134 char shelp
[] = "send file";
135 char rhelp
[] = "receive file";
136 char mhelp
[] = "set file transfer mode";
137 char sthelp
[] = "show current status";
138 char xhelp
[] = "set per-packet retransmission timeout";
139 char ihelp
[] = "set total retransmission timeout";
140 char ashelp
[] = "set mode to netascii";
141 char bnhelp
[] = "set mode to octet";
143 struct cmd cmdtab
[] = {
144 { "connect", chelp
, setpeer
},
145 { "mode", mhelp
, modecmd
},
146 { "put", shelp
, put
},
147 { "get", rhelp
, get
},
148 { "quit", qhelp
, quit
},
149 { "verbose", vhelp
, setverbose
},
150 { "blksize", blhelp
, setblksize
},
151 { "tsize", tshelp
, settsize
},
152 { "trace", thelp
, settrace
},
153 { "status", sthelp
, status
},
154 { "binary", bnhelp
, setbinary
},
155 { "ascii", ashelp
, setascii
},
156 { "rexmt", xhelp
, setrexmt
},
157 { "timeout", ihelp
, settimeout
},
158 { "tout", tohelp
, settimeoutopt
},
159 { "?", hhelp
, help
},
171 strcpy(mode
, "netascii");
172 signal(SIGINT
, intr
);
174 setprogname(argv
[0]);
175 while ((c
= getopt(argc
, argv
, "e")) != -1) {
178 blksize
= MAXSEGSIZE
;
179 strcpy(mode
, "octet");
184 printf("usage: %s [-e] host-name [port]\n",
193 if (setjmp(toplevel
) != 0)
199 if (setjmp(toplevel
) != 0)
212 struct addrinfo hints
, *res0
, *res
;
214 struct sockaddr_storage ss
;
215 char *cause
= "unknown";
223 memset(&hints
, 0, sizeof(hints
));
224 hints
.ai_family
= PF_UNSPEC
;
225 hints
.ai_socktype
= SOCK_DGRAM
;
226 hints
.ai_protocol
= IPPROTO_UDP
;
227 hints
.ai_flags
= AI_CANONNAME
;
230 error
= getaddrinfo(host
, port
, &hints
, &res0
);
232 warnx("%s", gai_strerror(error
));
236 for (res
= res0
; res
; res
= res
->ai_next
) {
237 if (res
->ai_addrlen
> sizeof(peeraddr
))
239 f
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
245 memset(&ss
, 0, sizeof(ss
));
246 ss
.ss_family
= res
->ai_family
;
247 ss
.ss_len
= res
->ai_addrlen
;
248 if (bind(f
, (struct sockaddr
*)&ss
, ss
.ss_len
) < 0) {
260 if (setsockopt(f
, SOL_SOCKET
, SO_SNDBUF
, &soopt
, sizeof(soopt
))
264 cause
= "setsockopt SNDBUF";
266 if (setsockopt(f
, SOL_SOCKET
, SO_RCVBUF
, &soopt
, sizeof(soopt
))
270 cause
= "setsockopt RCVBUF";
277 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
278 memcpy(&peeraddr
, res
->ai_addr
, res
->ai_addrlen
);
279 if (res
->ai_canonname
) {
280 (void) strlcpy(hostname
, res
->ai_canonname
,
283 (void) strlcpy(hostname
, host
, sizeof(hostname
));
297 strcpy(line
, "Connect ");
299 fgets(&line
[strlen(line
)], LBUFLEN
-strlen(line
), stdin
);
304 if ((argc
< 2) || (argc
> 3)) {
305 printf("usage: %s [-e] host-name [port]\n", getprogname());
309 setpeer0(argv
[1], NULL
);
311 setpeer0(argv
[1], argv
[2]);
318 { "ascii", "netascii" },
319 { "netascii", "netascii" },
320 { "binary", "octet" },
321 { "image", "octet" },
322 { "octet", "octet" },
323 /* { "mail", "mail" }, */
336 printf("Using %s mode to transfer files.\n", mode
);
340 for (p
= modes
; p
->m_name
; p
++)
341 if (strcmp(argv
[1], p
->m_name
) == 0)
344 settftpmode(p
->m_mode
);
347 printf("%s: unknown mode\n", argv
[1]);
348 /* drop through and print usage message */
351 printf("usage: %s [", argv
[0]);
353 for (p
= modes
; p
->m_name
; p
++) {
354 printf("%s%s", sep
, p
->m_name
);
363 setbinary(argc
, argv
)
368 settftpmode("octet");
377 settftpmode("netascii");
384 strcpy(mode
, newmode
);
386 printf("mode set to %s\n", mode
);
403 strcpy(line
, "send ");
405 fgets(&line
[strlen(line
)], LBUFLEN
-strlen(line
), stdin
);
414 targ
= argv
[argc
- 1];
415 if (strrchr(argv
[argc
- 1], ':')) {
418 for (n
= 1; n
< argc
- 1; n
++)
419 if (strchr(argv
[n
], ':')) {
424 targ
= strrchr(cp
, ':');
426 if (cp
[0] == '[' && cp
[strlen(cp
) - 1] == ']') {
427 cp
[strlen(cp
) - 1] = '\0';
433 printf("No target machine specified.\n");
437 cp
= argc
== 2 ? tail(targ
) : argv
[1];
438 fd
= open(cp
, O_RDONLY
);
444 printf("putting %s to %s:%s [%s]\n",
445 cp
, hostname
, targ
, mode
);
446 sendfile(fd
, targ
, mode
);
449 /* this assumes the target is a directory */
450 /* on a remote unix system. hmmmm. */
451 cp
= strchr(targ
, '\0');
453 for (n
= 1; n
< argc
- 1; n
++) {
454 strcpy(cp
, tail(argv
[n
]));
455 fd
= open(argv
[n
], O_RDONLY
);
461 printf("putting %s to %s:%s [%s]\n",
462 argv
[n
], hostname
, targ
, mode
);
463 sendfile(fd
, targ
, mode
);
471 printf("usage: %s file ... host:target, or\n", s
);
472 printf(" %s file ... target (when already connected)\n", s
);
489 strcpy(line
, "get ");
491 fgets(&line
[strlen(line
)], LBUFLEN
-strlen(line
), stdin
);
501 for (n
= 1; n
< argc
; n
++)
502 if (strrchr(argv
[n
], ':') == 0) {
507 for (n
= 1; n
< argc
; n
++) {
508 src
= strrchr(argv
[n
], ':');
515 if (cp
[0] == '[' && cp
[strlen(cp
) - 1] == ']') {
516 cp
[strlen(cp
) - 1] = '\0';
524 cp
= argc
== 3 ? argv
[2] : tail(src
);
525 fd
= creat(cp
, 0644);
531 printf("getting from %s:%s to %s [%s]\n",
532 hostname
, src
, cp
, mode
);
533 recvfile(fd
, src
, mode
);
536 cp
= tail(src
); /* new .. jdg */
537 fd
= creat(cp
, 0644);
543 printf("getting from %s:%s to %s [%s]\n",
544 hostname
, src
, cp
, mode
);
545 recvfile(fd
, src
, mode
);
553 printf("usage: %s host:file host:file ... file, or\n", s
);
554 printf(" %s file file ... file if connected\n", s
);
558 setblksize(argc
, argv
)
565 strcpy(line
, "blksize ");
566 printf("(blksize) ");
567 fgets(&line
[strlen(line
)], LBUFLEN
-strlen(line
), stdin
);
573 printf("usage: %s value\n", argv
[0]);
577 if (t
< 8 || t
> 65464)
578 printf("%s: bad value\n", argv
[1]);
583 int def_rexmtval
= TIMEOUT
;
584 int rexmtval
= TIMEOUT
;
594 strcpy(line
, "Rexmt-timeout ");
596 fgets(&line
[strlen(line
)], LBUFLEN
-strlen(line
), stdin
);
602 printf("usage: %s value\n", argv
[0]);
607 printf("%s: bad value\n", argv
[1]);
612 int maxtimeout
= 5 * TIMEOUT
;
615 settimeout(argc
, argv
)
622 strcpy(line
, "Maximum-timeout ");
624 fgets(&line
[strlen(line
)], LBUFLEN
-strlen(line
), stdin
);
630 printf("usage: %s value\n", argv
[0]);
635 printf("%s: bad value\n", argv
[1]);
646 printf("Connected to %s.\n", hostname
);
648 printf("Not connected.\n");
649 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
,
650 verbose
? "on" : "off", trace
? "on" : "off");
651 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
652 rexmtval
, maxtimeout
);
660 signal(SIGALRM
, SIG_IGN
);
662 longjmp(toplevel
, -1);
672 s
= strrchr(filename
, '/');
691 printf("%s> ", prompt
);
692 if (fgets(line
, LBUFLEN
, stdin
) == 0) {
699 if ((line
[0] == 0) || (line
[0] == '\n'))
704 c
= getcmd(margv
[0]);
705 if (c
== (struct cmd
*)-1) {
706 printf("?Ambiguous command\n");
710 printf("?Invalid command\n");
713 (*c
->handler
)(margc
, margv
);
722 struct cmd
*c
, *found
;
723 int nmatches
, longest
;
728 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
729 for (q
= name
; *q
== *p
++; q
++)
730 if (*q
== 0) /* exact match? */
732 if (!*q
) { /* the name was a prefix */
733 if (q
- name
> longest
) {
737 } else if (q
- name
== longest
)
742 return ((struct cmd
*)-1);
747 * Slice a string up into argc/argv.
756 for (cp
= line
; *cp
;) {
757 while (isspace((unsigned char)*cp
))
763 while (*cp
!= '\0' && !isspace((unsigned char)*cp
))
792 printf("Commands may be abbreviated. Commands are:\n\n");
793 for (c
= cmdtab
; c
->name
; c
++)
794 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
801 if (c
== (struct cmd
*)-1)
802 printf("?Ambiguous help command %s\n", arg
);
803 else if (c
== (struct cmd
*)0)
804 printf("?Invalid help command %s\n", arg
);
806 printf("%s\n", c
->help
);
816 printf("Packet tracing %s.\n", trace
? "on" : "off");
820 setverbose(argc
, argv
)
825 printf("Verbose mode %s.\n", verbose
? "on" : "off");
834 printf("Tsize mode %s.\n", tsize
? "on" : "off");
838 settimeoutopt(argc
, argv
)
843 printf("Timeout option %s.\n", tout
? "on" : "off");