1 /* $NetBSD: main.c,v 1.25 2006/10/22 16:44:46 christos 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\
35 The Regents of the University of California. All rights reserved.");
37 static char sccsid
[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
39 __RCSID("$NetBSD: main.c,v 1.25 2006/10/22 16:44:46 christos 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>
54 #include <arpa/tftp.h>
70 #define TIMEOUT 5 /* secs between rexmt's */
71 #define LBUFLEN 200 /* size of input buffer */
73 struct sockaddr_storage peeraddr
;
80 size_t def_blksize
=SEGSIZE
;
81 size_t blksize
=SEGSIZE
;
82 in_addr_t mcaddr
= INADDR_NONE
;
90 const char *prompt
= "tftp";
93 void get
__P((int, char **));
94 void help
__P((int, char **));
95 void modecmd
__P((int, char **));
96 void put
__P((int, char **));
97 void quit
__P((int, char **));
98 void setascii
__P((int, char **));
99 void setbinary
__P((int, char **));
100 void setpeer0
__P((const char *, const char *));
101 void setpeer
__P((int, char **));
102 void setrexmt
__P((int, char **));
103 void settimeout
__P((int, char **));
104 void settrace
__P((int, char **));
105 void setverbose
__P((int, char **));
106 void setblksize
__P((int, char **));
107 void settsize
__P((int, char **));
108 void settimeoutopt
__P((int, char **));
109 void status
__P((int, char **));
110 char *tail
__P((char *));
111 int main
__P((int, char *[]));
112 void intr
__P((int));
113 const struct cmd
*getcmd
__P((char *));
115 static __dead
void command
__P((void));
117 static void getusage
__P((char *));
118 static void makeargv
__P((void));
119 static void putusage
__P((char *));
120 static void settftpmode
__P((const char *));
122 #define HELPINDENT (sizeof("connect"))
127 void (*handler
) __P((int, char **));
130 const char vhelp
[] = "toggle verbose mode";
131 const char thelp
[] = "toggle packet tracing";
132 const char tshelp
[] = "toggle extended tsize option";
133 const char tohelp
[] = "toggle extended timeout option";
134 const char blhelp
[] = "set an alternative blocksize (def. 512)";
135 const char chelp
[] = "connect to remote tftp";
136 const char qhelp
[] = "exit tftp";
137 const char hhelp
[] = "print help information";
138 const char shelp
[] = "send file";
139 const char rhelp
[] = "receive file";
140 const char mhelp
[] = "set file transfer mode";
141 const char sthelp
[] = "show current status";
142 const char xhelp
[] = "set per-packet retransmission timeout";
143 const char ihelp
[] = "set total retransmission timeout";
144 const char ashelp
[] = "set mode to netascii";
145 const char bnhelp
[] = "set mode to octet";
147 const struct cmd cmdtab
[] = {
148 { "connect", chelp
, setpeer
},
149 { "mode", mhelp
, modecmd
},
150 { "put", shelp
, put
},
151 { "get", rhelp
, get
},
152 { "quit", qhelp
, quit
},
153 { "verbose", vhelp
, setverbose
},
154 { "blksize", blhelp
, setblksize
},
155 { "tsize", tshelp
, settsize
},
156 { "trace", thelp
, settrace
},
157 { "status", sthelp
, status
},
158 { "binary", bnhelp
, setbinary
},
159 { "ascii", ashelp
, setascii
},
160 { "rexmt", xhelp
, setrexmt
},
161 { "timeout", ihelp
, settimeout
},
162 { "tout", tohelp
, settimeoutopt
},
163 { "?", hhelp
, help
},
175 (void)strlcpy(mode
, "netascii", sizeof(mode
));
176 (void)signal(SIGINT
, intr
);
178 setprogname(argv
[0]);
179 while ((c
= getopt(argc
, argv
, "e")) != -1) {
182 blksize
= MAXSEGSIZE
;
183 (void)strlcpy(mode
, "octet", sizeof(mode
));
188 (void)printf("usage: %s [-e] host-name [port]\n",
197 if (setjmp(toplevel
) != 0)
203 if (setjmp(toplevel
) != 0)
216 struct addrinfo hints
, *res0
, *res
;
218 struct sockaddr_storage ss
;
219 const char *cause
= "unknown";
227 (void)memset(&hints
, 0, sizeof(hints
));
228 hints
.ai_family
= PF_UNSPEC
;
229 hints
.ai_socktype
= SOCK_DGRAM
;
230 hints
.ai_protocol
= IPPROTO_UDP
;
231 hints
.ai_flags
= AI_CANONNAME
;
234 error
= getaddrinfo(host
, port
, &hints
, &res0
);
236 warnx("%s", gai_strerror(error
));
240 for (res
= res0
; res
; res
= res
->ai_next
) {
241 if (res
->ai_addrlen
> sizeof(peeraddr
))
243 f
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
249 (void)memset(&ss
, 0, sizeof(ss
));
250 ss
.ss_family
= res
->ai_family
;
251 ss
.ss_len
= res
->ai_addrlen
;
252 if (bind(f
, (struct sockaddr
*)(void *)&ss
,
253 (socklen_t
)ss
.ss_len
) < 0) {
265 if (setsockopt(f
, SOL_SOCKET
, SO_SNDBUF
, &soopt
, sizeof(soopt
))
269 cause
= "setsockopt SNDBUF";
271 else if (setsockopt(f
, SOL_SOCKET
, SO_RCVBUF
, &soopt
, sizeof(soopt
))
275 cause
= "setsockopt RCVBUF";
279 if (f
< 0 || res
== NULL
)
282 /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
283 (void)memcpy(&peeraddr
, res
->ai_addr
, res
->ai_addrlen
);
284 if (res
->ai_canonname
) {
285 (void)strlcpy(hostname
, res
->ai_canonname
,
288 (void)strlcpy(hostname
, host
, sizeof(hostname
));
302 (void)strlcpy(line
, "Connect ", sizeof(line
));
303 (void)printf("(to) ");
304 (void)fgets(&line
[strlen(line
)], (int)(LBUFLEN
-strlen(line
)), stdin
);
309 if ((argc
< 2) || (argc
> 3)) {
310 (void)printf("usage: %s [-e] host-name [port]\n", getprogname());
314 setpeer0(argv
[1], NULL
);
316 setpeer0(argv
[1], argv
[2]);
323 { "ascii", "netascii" },
324 { "netascii", "netascii" },
325 { "binary", "octet" },
326 { "image", "octet" },
327 { "octet", "octet" },
328 /* { "mail", "mail" }, */
341 (void)printf("Using %s mode to transfer files.\n", mode
);
345 for (p
= modes
; p
->m_name
; p
++)
346 if (strcmp(argv
[1], p
->m_name
) == 0)
349 settftpmode(p
->m_mode
);
352 (void)printf("%s: unknown mode\n", argv
[1]);
353 /* drop through and print usage message */
356 (void)printf("usage: %s [", argv
[0]);
358 for (p
= modes
; p
->m_name
; p
++) {
359 (void)printf("%s%s", sep
, p
->m_name
);
363 (void)printf(" ]\n");
369 setbinary(argc
, argv
)
374 settftpmode("octet");
384 settftpmode("netascii");
391 (void)strlcpy(mode
, newmode
, sizeof(mode
));
393 (void)printf("mode set to %s\n", mode
);
410 (void)strlcpy(line
, "send ", sizeof(line
));
411 (void)printf("(file) ");
412 (void)fgets(&line
[strlen(line
)], (int)(LBUFLEN
-strlen(line
)), stdin
);
421 targ
= argv
[argc
- 1];
422 if (strrchr(argv
[argc
- 1], ':')) {
425 for (n
= 1; n
< argc
- 1; n
++)
426 if (strchr(argv
[n
], ':')) {
431 targ
= strrchr(cp
, ':');
433 if (cp
[0] == '[' && cp
[strlen(cp
) - 1] == ']') {
434 cp
[strlen(cp
) - 1] = '\0';
440 (void)printf("No target machine specified.\n");
444 char *cp
= argc
== 2 ? tail(targ
) : argv
[1];
445 fd
= open(cp
, O_RDONLY
);
451 (void)printf("putting %s to %s:%s [%s]\n",
452 cp
, hostname
, targ
, mode
);
453 sendfile(fd
, targ
, mode
);
456 /* this assumes the target is a directory */
457 /* on a remote unix system. hmmmm. */
458 p
= strchr(targ
, '\0');
460 for (n
= 1; n
< argc
- 1; n
++) {
461 (void)strcpy(p
, tail(argv
[n
]));
462 fd
= open(argv
[n
], O_RDONLY
);
468 (void)printf("putting %s to %s:%s [%s]\n",
469 argv
[n
], hostname
, targ
, mode
);
470 sendfile(fd
, targ
, mode
);
478 (void)printf("usage: %s file ... host:target, or\n", s
);
479 (void)printf(" %s file ... target (when already connected)\n", s
);
496 (void)strlcpy(line
, "get ", sizeof(line
));
497 (void)printf("(files) ");
498 (void)fgets(&line
[strlen(line
)], (int)(LBUFLEN
-strlen(line
)), stdin
);
508 for (n
= 1; n
< argc
; n
++)
509 if (strrchr(argv
[n
], ':') == 0) {
514 for (n
= 1; n
< argc
; n
++) {
515 src
= strrchr(argv
[n
], ':');
522 if (cp
[0] == '[' && cp
[strlen(cp
) - 1] == ']') {
523 cp
[strlen(cp
) - 1] = '\0';
531 char *cp
= argc
== 3 ? argv
[2] : tail(src
);
532 fd
= creat(cp
, 0644);
538 (void)printf("getting from %s:%s to %s [%s]\n",
539 hostname
, src
, cp
, mode
);
540 recvfile(fd
, src
, mode
);
543 p
= tail(src
); /* new .. jdg */
550 (void)printf("getting from %s:%s to %s [%s]\n",
551 hostname
, src
, p
, mode
);
552 recvfile(fd
, src
, mode
);
560 (void)printf("usage: %s host:file host:file ... file, or\n", s
);
561 (void)printf(" %s file file ... file if connected\n", s
);
565 setblksize(argc
, argv
)
572 (void)strlcpy(line
, "blksize ", sizeof(line
));
573 (void)printf("(blksize) ");
574 (void)fgets(&line
[strlen(line
)], (int)(LBUFLEN
-strlen(line
)), stdin
);
580 (void)printf("usage: %s value\n", argv
[0]);
584 if (t
< 8 || t
> 65464)
585 (void)printf("%s: bad value\n", argv
[1]);
590 unsigned int def_rexmtval
= TIMEOUT
;
591 unsigned int rexmtval
= TIMEOUT
;
601 (void)strlcpy(line
, "Rexmt-timeout ", sizeof(line
));
602 (void)printf("(value) ");
603 (void)fgets(&line
[strlen(line
)], (int)(LBUFLEN
-strlen(line
)), stdin
);
609 (void)printf("usage: %s value\n", argv
[0]);
614 (void)printf("%s: bad value\n", argv
[1]);
619 int maxtimeout
= 5 * TIMEOUT
;
622 settimeout(argc
, argv
)
629 (void)strlcpy(line
, "Maximum-timeout ", sizeof(line
));
630 (void)printf("(value) ");
631 (void)fgets(&line
[strlen(line
)], (int)(LBUFLEN
-strlen(line
)), stdin
);
637 (void)printf("usage: %s value\n", argv
[0]);
642 (void)printf("%s: bad value\n", argv
[1]);
654 (void)printf("Connected to %s.\n", hostname
);
656 (void)printf("Not connected.\n");
657 (void)printf("Mode: %s Verbose: %s Tracing: %s\n", mode
,
658 verbose
? "on" : "off", trace
? "on" : "off");
659 (void)printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
660 rexmtval
, maxtimeout
);
669 (void)signal(SIGALRM
, SIG_IGN
);
671 longjmp(toplevel
, -1);
681 s
= strrchr(filename
, '/');
700 (void)printf("%s> ", prompt
);
701 if (fgets(line
, LBUFLEN
, stdin
) == 0) {
708 if ((line
[0] == 0) || (line
[0] == '\n'))
713 c
= getcmd(margv
[0]);
714 if (c
== (struct cmd
*)-1) {
715 (void)printf("?Ambiguous command\n");
719 (void)printf("?Invalid command\n");
722 (*c
->handler
)(margc
, margv
);
731 const struct cmd
*c
, *found
;
732 int nmatches
, longest
;
737 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
738 for (q
= name
; *q
== *p
++; q
++)
739 if (*q
== 0) /* exact match? */
741 if (!*q
) { /* the name was a prefix */
742 if (q
- name
> longest
) {
746 } else if (q
- name
== longest
)
751 return ((struct cmd
*)-1);
756 * Slice a string up into argc/argv.
765 for (cp
= line
; *cp
;) {
766 while (isspace((unsigned char)*cp
))
772 while (*cp
!= '\0' && !isspace((unsigned char)*cp
))
802 (void)printf("Commands may be abbreviated. Commands are:\n\n");
803 for (c
= cmdtab
; c
->name
; c
++)
804 (void)printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
811 if (c
== (struct cmd
*)-1)
812 (void)printf("?Ambiguous help command %s\n", arg
);
813 else if (c
== (struct cmd
*)0)
814 (void)printf("?Invalid help command %s\n", arg
);
816 (void)printf("%s\n", c
->help
);
827 (void)printf("Packet tracing %s.\n", trace
? "on" : "off");
832 setverbose(argc
, argv
)
837 (void)printf("Verbose mode %s.\n", verbose
? "on" : "off");
847 (void)printf("Tsize mode %s.\n", tsize
? "on" : "off");
852 settimeoutopt(argc
, argv
)
857 (void)printf("Timeout option %s.\n", tout
? "on" : "off");