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
34 #include "common/tftpsubs.h"
36 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
39 * TFTP User Program -- Command Interface.
44 #include <readline/readline.h>
45 #ifdef HAVE_READLINE_HISTORY_H
46 #include <readline/history.h>
52 #define TIMEOUT 5 /* secs between rexmt's */
53 #define LBUFLEN 200 /* size of input buffer */
61 static const struct modes modes
[] = {
62 {"netascii", "netascii", O_TEXT
},
63 {"ascii", "netascii", O_TEXT
},
64 {"octet", "octet", O_BINARY
},
65 {"binary", "octet", O_BINARY
},
66 {"image", "octet", O_BINARY
},
70 #define MODE_OCTET (&modes[2])
71 #define MODE_NETASCII (&modes[0])
72 #define MODE_DEFAULT MODE_NETASCII
75 int ai_fam
= AF_UNSPEC
;
76 int ai_fam_sock
= AF_UNSPEC
;
79 int ai_fam_sock
= AF_INET
;
82 union sock_addr peeraddr
;
89 const struct modes
*mode
;
97 const char *prompt
= "tftp> ";
102 unsigned int portrange_from
= 0;
103 unsigned int portrange_to
= 0;
105 void get(int, char **);
106 void help(int, char **);
107 void modecmd(int, char **);
108 void put(int, char **);
109 void quit(int, char **);
110 void setascii(int, char **);
111 void setbinary(int, char **);
112 void setpeer(int, char **);
113 void setrexmt(int, char **);
114 void settimeout(int, char **);
115 void settrace(int, char **);
116 void setverbose(int, char **);
117 void status(int, char **);
118 void setliteral(int, char **);
120 static void command(void);
122 static void getusage(char *);
123 static void makeargv(void);
124 static void putusage(char *);
125 static void settftpmode(const struct modes
*);
127 #define HELPINDENT (sizeof("connect"))
132 void (*handler
) (int, char **);
135 struct cmd cmdtab
[] = {
137 "connect to remote tftp",
140 "set file transfer mode",
152 "toggle verbose mode",
155 "toggle packet tracing",
158 "toggle literal mode, ignore ':' in file name",
161 "show current status",
167 "set mode to netascii",
170 "set per-packet transmission timeout",
173 "set total retransmission timeout",
176 "print help information",
179 "print help information",
184 struct cmd
*getcmd(char *);
187 char *xstrdup(const char *);
191 static void usage(int errcode
)
195 "Usage: %s [-4][-6][-v][-l][-m mode] [host [port]] [-c command]\n",
197 "Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n",
203 int main(int argc
, char *argv
[])
207 static int pargc
, peerargc
;
208 static int iscmd
= 0;
217 peerargv
[0] = argv
[0];
220 for (arg
= 1; !iscmd
&& arg
< argc
; arg
++) {
221 if (argv
[arg
][0] == '-') {
222 for (optx
= &argv
[arg
][1]; *optx
; optx
++) {
236 /* Print version and configuration to stdout and exit */
237 printf("%s\n", TFTP_CONFIG_STR
);
246 const struct modes
*p
;
248 for (p
= modes
; p
->m_name
; p
++) {
249 if (!strcmp(argv
[arg
], p
->m_name
))
255 fprintf(stderr
, "%s: invalid mode: %s\n",
268 (argv
[arg
], "%u:%u", &portrange_from
,
270 || portrange_from
> portrange_to
271 || portrange_to
> 65535) {
272 fprintf(stderr
, "Bad port range: %s\n", argv
[arg
]);
279 usage(*optx
== 'h' ? 0 : EX_USAGE
);
286 peerargv
[peerargc
++] = argv
[arg
];
290 ai_fam_sock
= ai_fam
;
295 sp
= getservbyname("tftp", "udp");
297 /* Use canned values */
300 "tftp: tftp/udp: unknown service, faking it...\n");
301 sp
= xmalloc(sizeof(struct servent
));
302 sp
->s_name
= (char *)"tftp";
303 sp
->s_aliases
= NULL
;
304 sp
->s_port
= htons(IPPORT_TFTP
);
305 sp
->s_proto
= (char *)"udp";
308 tftp_signal(SIGINT
, intr
, 0);
312 if (sigsetjmp(toplevel
, 1) != 0)
314 setpeer(peerargc
, peerargv
);
317 if (ai_fam_sock
== AF_UNSPEC
)
318 ai_fam_sock
= AF_INET
;
320 f
= socket(ai_fam_sock
, SOCK_DGRAM
, 0);
322 perror("tftp: socket");
325 bzero(&sa
, sizeof(sa
));
326 sa
.sa
.sa_family
= ai_fam_sock
;
327 if (pick_port_bind(f
, &sa
, portrange_from
, portrange_to
)) {
328 perror("tftp: bind");
332 if (iscmd
&& pargc
) {
333 /* -c specified; execute command and exit */
336 if (sigsetjmp(toplevel
, 1) != 0)
337 exit(EX_UNAVAILABLE
);
339 c
= getcmd(pargv
[0]);
340 if (c
== (struct cmd
*)-1 || c
== (struct cmd
*)0) {
341 fprintf(stderr
, "%s: invalid command: %s\n", argv
[0],
345 (*c
->handler
) (pargc
, pargv
);
349 #ifdef HAVE_READLINE_HISTORY_H
354 if (sigsetjmp(toplevel
, 1) != 0)
358 return 0; /* Never reached */
363 /* Called when a command is incomplete; modifies
364 the global variable "line" */
365 static void getmoreargs(const char *partial
, const char *mprompt
)
371 len
= strlen(partial
);
372 eline
= readline(mprompt
);
376 elen
= strlen(eline
);
382 line
= xmalloc(len
+ elen
+ 1);
383 strcpy(line
, partial
);
384 strcpy(line
+ len
, eline
);
387 #ifdef HAVE_READLINE_HISTORY_H
391 int len
= strlen(partial
);
393 strcpy(line
, partial
);
394 fputs(mprompt
, stdout
);
395 if (fgets(line
+ len
, LBUFLEN
- len
, stdin
) == 0)
401 void setpeer(int argc
, char *argv
[])
406 getmoreargs("connect ", "(to) ");
411 if ((argc
< 2) || (argc
> 3)) {
412 printf("usage: %s host-name [port]\n", argv
[0]);
416 peeraddr
.sa
.sa_family
= ai_fam
;
417 err
= set_sock_addr(argv
[1], &peeraddr
, &hostname
);
419 printf("Error: %s\n", gai_strerror(err
));
420 printf("%s: unknown host\n", argv
[1]);
424 ai_fam
= peeraddr
.sa
.sa_family
;
425 if (f
== -1) { /* socket not open */
426 ai_fam_sock
= ai_fam
;
427 } else { /* socket was already open */
428 if (ai_fam_sock
!= ai_fam
) { /* need reopen socken for new family */
432 ai_fam_sock
= ai_fam
;
433 f
= socket(ai_fam_sock
, SOCK_DGRAM
, 0);
435 perror("tftp: socket");
438 bzero((char *)&sa
, sizeof (sa
));
439 sa
.sa
.sa_family
= ai_fam_sock
;
440 if (pick_port_bind(f
, &sa
, portrange_from
, portrange_to
)) {
441 perror("tftp: bind");
449 usp
= getservbyname(argv
[2], "udp");
453 unsigned long myport
;
455 myport
= strtoul(argv
[2], &ep
, 10);
456 if (*ep
|| myport
> 65535UL) {
457 printf("%s: bad port number\n", argv
[2]);
461 port
= htons((u_short
) myport
);
466 char tmp
[INET6_ADDRSTRLEN
], *tp
;
467 tp
= (char *)inet_ntop(peeraddr
.sa
.sa_family
, SOCKADDR_P(&peeraddr
),
468 tmp
, INET6_ADDRSTRLEN
);
471 printf("Connected to %s (%s), port %u\n",
472 hostname
, tp
, (unsigned int)ntohs(port
));
477 void modecmd(int argc
, char *argv
[])
479 const struct modes
*p
;
483 printf("Using %s mode to transfer files.\n", mode
->m_mode
);
487 for (p
= modes
; p
->m_name
; p
++)
488 if (strcmp(argv
[1], p
->m_name
) == 0)
494 printf("%s: unknown mode\n", argv
[1]);
495 /* drop through and print usage message */
498 printf("usage: %s [", argv
[0]);
500 for (p
= modes
; p
->m_name
; p
++) {
501 printf("%s%s", sep
, p
->m_name
);
509 void setbinary(int argc
, char *argv
[])
512 (void)argv
; /* Quiet unused warning */
513 settftpmode(MODE_OCTET
);
516 void setascii(int argc
, char *argv
[])
519 (void)argv
; /* Quiet unused warning */
520 settftpmode(MODE_NETASCII
);
523 static void settftpmode(const struct modes
*newmode
)
527 printf("mode set to %s\n", mode
->m_mode
);
533 void put(int argc
, char *argv
[])
540 getmoreargs("send ", "(file) ");
549 targ
= argv
[argc
- 1];
550 if (!literal
&& strchr(argv
[argc
- 1], ':')) {
551 for (n
= 1; n
< argc
- 1; n
++)
552 if (strchr(argv
[n
], ':')) {
557 targ
= strchr(cp
, ':');
559 peeraddr
.sa
.sa_family
= ai_fam
;
560 err
= set_sock_addr(cp
, &peeraddr
,&hostname
);
562 printf("Error: %s\n", gai_strerror(err
));
563 printf("%s: unknown host\n", argv
[1]);
567 ai_fam
= peeraddr
.sa
.sa_family
;
571 printf("No target machine specified.\n");
575 cp
= argc
== 2 ? tail(targ
) : argv
[1];
576 fd
= open(cp
, O_RDONLY
| mode
->m_openflags
);
578 fprintf(stderr
, "tftp: ");
583 printf("putting %s to %s:%s [%s]\n",
584 cp
, hostname
, targ
, mode
->m_mode
);
585 sa_set_port(&peeraddr
, port
);
586 tftp_sendfile(fd
, targ
, mode
->m_mode
);
589 /* this assumes the target is a directory */
590 /* on a remote unix system. hmmmm. */
591 cp
= strchr(targ
, '\0');
593 for (n
= 1; n
< argc
- 1; n
++) {
594 strcpy(cp
, tail(argv
[n
]));
595 fd
= open(argv
[n
], O_RDONLY
| mode
->m_openflags
);
597 fprintf(stderr
, "tftp: ");
602 printf("putting %s to %s:%s [%s]\n",
603 argv
[n
], hostname
, targ
, mode
->m_mode
);
604 sa_set_port(&peeraddr
, port
);
605 tftp_sendfile(fd
, targ
, mode
->m_mode
);
609 static void putusage(char *s
)
611 printf("usage: %s file ... host:target, or\n", s
);
612 printf(" %s file ... target (when already connected)\n", s
);
618 void get(int argc
, char *argv
[])
626 getmoreargs("get ", "(files) ");
636 for (n
= 1; n
< argc
; n
++)
637 if (literal
|| strchr(argv
[n
], ':') == 0) {
642 for (n
= 1; n
< argc
; n
++) {
643 src
= strchr(argv
[n
], ':');
644 if (literal
|| src
== NULL
)
650 peeraddr
.sa
.sa_family
= ai_fam
;
651 err
= set_sock_addr(argv
[n
], &peeraddr
, &hostname
);
653 printf("Warning: %s\n", gai_strerror(err
));
654 printf("%s: unknown host\n", argv
[1]);
657 ai_fam
= peeraddr
.sa
.sa_family
;
661 cp
= argc
== 3 ? argv
[2] : tail(src
);
662 fd
= open(cp
, O_WRONLY
| O_CREAT
| O_TRUNC
| mode
->m_openflags
,
665 fprintf(stderr
, "tftp: ");
670 printf("getting from %s:%s to %s [%s]\n",
671 hostname
, src
, cp
, mode
->m_mode
);
672 sa_set_port(&peeraddr
, port
);
673 tftp_recvfile(fd
, src
, mode
->m_mode
);
676 cp
= tail(src
); /* new .. jdg */
677 fd
= open(cp
, O_WRONLY
| O_CREAT
| O_TRUNC
| mode
->m_openflags
,
680 fprintf(stderr
, "tftp: ");
685 printf("getting from %s:%s to %s [%s]\n",
686 hostname
, src
, cp
, mode
->m_mode
);
687 sa_set_port(&peeraddr
, port
);
688 tftp_recvfile(fd
, src
, mode
->m_mode
);
692 static void getusage(char *s
)
694 printf("usage: %s host:file host:file ... file, or\n", s
);
695 printf(" %s file file ... file if connected\n", s
);
698 int rexmtval
= TIMEOUT
;
700 void setrexmt(int argc
, char *argv
[])
705 getmoreargs("rexmt-timeout ", "(value) ");
711 printf("usage: %s value\n", argv
[0]);
716 printf("%s: bad value\n", argv
[1]);
721 int maxtimeout
= 5 * TIMEOUT
;
723 void settimeout(int argc
, char *argv
[])
728 getmoreargs("maximum-timeout ", "(value) ");
734 printf("usage: %s value\n", argv
[0]);
739 printf("%s: bad value\n", argv
[1]);
744 void setliteral(int argc
, char *argv
[])
747 (void)argv
; /* Quiet unused warning */
749 printf("Literal mode %s.\n", literal
? "on" : "off");
752 void status(int argc
, char *argv
[])
755 (void)argv
; /* Quiet unused warning */
757 printf("Connected to %s.\n", hostname
);
759 printf("Not connected.\n");
760 printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode
->m_mode
,
761 verbose
? "on" : "off", trace
? "on" : "off",
762 literal
? "on" : "off");
763 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
764 rexmtval
, maxtimeout
);
769 (void)sig
; /* Quiet unused warning */
772 tftp_signal(SIGALRM
, SIG_DFL
, 0);
773 siglongjmp(toplevel
, -1);
776 char *tail(char *filename
)
781 s
= strrchr(filename
, '/');
794 static void command(void)
804 line
= readline(prompt
);
808 fputs(prompt
, stdout
);
809 if (fgets(line
, LBUFLEN
, stdin
) == 0) {
817 if ((line
[0] == 0) || (line
[0] == '\n'))
820 #ifdef HAVE_READLINE_HISTORY_H
828 c
= getcmd(margv
[0]);
829 if (c
== (struct cmd
*)-1) {
830 printf("?Ambiguous command\n");
834 printf("?Invalid command\n");
837 (*c
->handler
) (margc
, margv
);
841 struct cmd
*getcmd(char *name
)
845 struct cmd
*c
, *found
;
846 int nmatches
, longest
;
851 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
852 for (q
= name
; *q
== *p
++; q
++)
853 if (*q
== 0) /* exact match? */
855 if (!*q
) { /* the name was a prefix */
856 if (q
- name
> longest
) {
860 } else if (q
- name
== longest
)
865 return ((struct cmd
*)-1);
870 * Slice a string up into argc/argv.
872 static void makeargv(void)
878 for (cp
= line
; *cp
;) {
885 while (*cp
!= '\0' && !isspace(*cp
))
894 void quit(int argc
, char *argv
[])
897 (void)argv
; /* Quiet unused warning */
904 void help(int argc
, char *argv
[])
908 printf("%s\n", VERSION
);
911 printf("Commands may be abbreviated. Commands are:\n\n");
912 for (c
= cmdtab
; c
->name
; c
++)
913 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
920 if (c
== (struct cmd
*)-1)
921 printf("?Ambiguous help command %s\n", arg
);
922 else if (c
== (struct cmd
*)0)
923 printf("?Invalid help command %s\n", arg
);
925 printf("%s\n", c
->help
);
929 void settrace(int argc
, char *argv
[])
932 (void)argv
; /* Quiet unused warning */
935 printf("Packet tracing %s.\n", trace
? "on" : "off");
938 void setverbose(int argc
, char *argv
[])
941 (void)argv
; /* Quiet unused warning */
944 printf("Verbose mode %s.\n", verbose
? "on" : "off");