1 /* $OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert Exp $ */
2 /* $NetBSD: main.c,v 1.6 1995/05/21 16:54:10 mycroft Exp $ */
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 static const char *copyright UNUSED
=
41 "@(#) Copyright (c) 1983, 1993\n\
42 The Regents of the University of California. All rights reserved.\n";
43 /* static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; */
44 /* static char rcsid[] = "$OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert Exp $"; */
45 static const char *rcsid UNUSED
=
49 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
52 * TFTP User Program -- Command Interface.
58 #include <readline/readline.h>
59 #ifdef HAVE_READLINE_HISTORY_H
60 #include <readline/history.h>
66 #define TIMEOUT 5 /* secs between rexmt's */
67 #define LBUFLEN 200 /* size of input buffer */
75 static const struct modes modes
[] = {
76 { "netascii", "netascii", O_TEXT
},
77 { "ascii", "netascii", O_TEXT
},
78 { "octet", "octet", O_BINARY
},
79 { "binary", "octet", O_BINARY
},
80 { "image", "octet", O_BINARY
},
83 #define MODE_OCTET (&modes[2])
84 #define MODE_NETASCII (&modes[0])
85 #define MODE_DEFAULT MODE_NETASCII
87 struct sockaddr_in peeraddr
;
93 const struct modes
*mode
;
101 const char *prompt
= "tftp> ";
106 void get (int, char **);
107 void help (int, char **);
108 void modecmd (int, char **);
109 void put (int, char **);
110 void quit (int, char **);
111 void setascii (int, char **);
112 void setbinary (int, char **);
113 void setpeer (int, char **);
114 void setrexmt (int, char **);
115 void settimeout (int, char **);
116 void settrace (int, char **);
117 void setverbose (int, char **);
118 void status (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 "show current status",
164 "set mode to netascii",
167 "set per-packet transmission timeout",
170 "set total retransmission timeout",
173 "print help information",
176 "print help information",
181 struct cmd
*getcmd(char *);
184 char *xstrdup(const char *);
188 static inline void usage(int errcode
)
190 fprintf(stderr
, "Usage: %s [-v][-m mode] [host [port]] [-c command]\n", program
);
195 main(int argc
, char *argv
[])
197 struct sockaddr_in s_in
;
199 static int pargc
, peerargc
;
200 static int iscmd
= 0;
209 peerargv
[0] = argv
[0];
212 for ( arg
= 1 ; !iscmd
&& arg
< argc
; arg
++ ) {
213 if ( argv
[arg
][0] == '-' ) {
214 for ( optx
= &argv
[arg
][1] ; *optx
; optx
++ ) {
220 /* Print version and configuration to stdout and exit */
221 printf("%s\n", TFTP_CONFIG_STR
);
227 const struct modes
*p
;
229 for ( p
= modes
; p
->m_name
; p
++ ) {
230 if (!strcmp(argv
[arg
], p
->m_name
))
236 fprintf(stderr
, "%s: invalid mode: %s\n", argv
[0], argv
[arg
]);
246 usage(*optx
== 'h' ? 0 : EX_USAGE
);
253 peerargv
[peerargc
++] = argv
[arg
];
260 sp
= getservbyname("tftp", "udp");
262 /* Use canned values */
264 fprintf(stderr
, "tftp: tftp/udp: unknown service, faking it...\n");
265 sp
= xmalloc(sizeof(struct servent
));
266 sp
->s_name
= (char *)"tftp";
267 sp
->s_aliases
= NULL
;
268 sp
->s_port
= htons(IPPORT_TFTP
);
269 sp
->s_proto
= (char *)"udp";
271 port
= sp
->s_port
; /* Default port */
272 f
= socket(AF_INET
, SOCK_DGRAM
, 0);
274 perror("tftp: socket");
277 bzero((char *)&s_in
, sizeof (s_in
));
278 s_in
.sin_family
= AF_INET
;
279 if (bind(f
, (struct sockaddr
*)&s_in
, sizeof (s_in
)) < 0) {
280 perror("tftp: bind");
283 bsd_signal(SIGINT
, intr
);
287 if (sigsetjmp(toplevel
,1) != 0)
289 setpeer(peerargc
, peerargv
);
292 if ( iscmd
&& pargc
) {
293 /* -c specified; execute command and exit */
296 if (sigsetjmp(toplevel
,1) != 0)
297 exit(EX_UNAVAILABLE
);
299 c
= getcmd(pargv
[0]);
300 if ( c
== (struct cmd
*)-1 || c
== (struct cmd
*)0 ) {
301 fprintf(stderr
, "%s: invalid command: %s\n", argv
[0], pargv
[1]);
304 (*c
->handler
)(pargc
, pargv
);
307 if (sigsetjmp(toplevel
,1) != 0)
311 #ifdef HAVE_READLINE_HISTORY_H
318 return 0; /* Never reached */
323 /* Called when a command is incomplete; modifies
324 the global variable "line" */
326 getmoreargs(const char *partial
, const char *mprompt
)
332 len
= strlen(partial
);
333 eline
= readline(mprompt
);
337 elen
= strlen(eline
);
341 line
= xmalloc(len
+elen
+1);
342 strcpy(line
, partial
);
343 strcpy(line
+len
, eline
);
346 #ifdef HAVE_READLINE_HISTORY_H
350 int len
= strlen(partial
);
352 strcpy(line
, partial
);
353 fputs(mprompt
, stdout
);
354 if ( fgets(line
+len
, LBUFLEN
-len
, stdin
) == 0 )
361 setpeer(int argc
, char *argv
[])
363 struct hostent
*host
;
366 getmoreargs("connect ", "(to) ");
371 if ((argc
< 2) || (argc
> 3)) {
372 printf("usage: %s host-name [port]\n", argv
[0]);
376 host
= gethostbyname(argv
[1]);
379 printf("%s: unknown host\n", argv
[1]);
382 peeraddr
.sin_family
= host
->h_addrtype
;
383 bcopy(host
->h_addr
, &peeraddr
.sin_addr
, host
->h_length
);
384 hostname
= xstrdup(host
->h_name
);
389 usp
= getservbyname(argv
[2], "udp");
393 unsigned long myport
;
395 myport
= strtoul(argv
[2], &ep
, 10);
396 if (*ep
|| myport
> 65535UL) {
397 printf("%s: bad port number\n", argv
[2]);
401 port
= htons((u_short
)myport
);
406 printf("Connected to %s (%s), port %u\n",
407 hostname
, inet_ntoa(peeraddr
.sin_addr
),
408 (unsigned int)ntohs(port
));
414 modecmd(int argc
, char *argv
[])
416 const struct modes
*p
;
420 printf("Using %s mode to transfer files.\n", mode
->m_mode
);
424 for (p
= modes
; p
->m_name
; p
++)
425 if (strcmp(argv
[1], p
->m_name
) == 0)
431 printf("%s: unknown mode\n", argv
[1]);
432 /* drop through and print usage message */
435 printf("usage: %s [", argv
[0]);
437 for (p
= modes
; p
->m_name
; p
++) {
438 printf("%s%s", sep
, p
->m_name
);
447 setbinary(int argc
, char *argv
[])
449 (void)argc
; (void)argv
; /* Quiet unused warning */
450 settftpmode(MODE_OCTET
);
454 setascii(int argc
, char *argv
[])
456 (void)argc
; (void)argv
; /* Quiet unused warning */
457 settftpmode(MODE_NETASCII
);
461 settftpmode(const struct modes
*newmode
)
465 printf("mode set to %s\n", mode
->m_mode
);
473 put(int argc
, char *argv
[])
480 getmoreargs("send ", "(file) ");
489 targ
= argv
[argc
- 1];
490 if (strchr(argv
[argc
- 1], ':')) {
493 for (n
= 1; n
< argc
- 1; n
++)
494 if (strchr(argv
[n
], ':')) {
499 targ
= strchr(cp
, ':');
501 hp
= gethostbyname(cp
);
503 fprintf(stderr
, "tftp: %s: ", cp
);
504 herror((char *)NULL
);
507 bcopy(hp
->h_addr
, &peeraddr
.sin_addr
, hp
->h_length
);
508 peeraddr
.sin_family
= hp
->h_addrtype
;
510 hostname
= xstrdup(hp
->h_name
);
513 printf("No target machine specified.\n");
517 cp
= argc
== 2 ? tail(targ
) : argv
[1];
518 fd
= open(cp
, O_RDONLY
|mode
->m_openflags
);
520 fprintf(stderr
, "tftp: "); perror(cp
);
524 printf("putting %s to %s:%s [%s]\n",
525 cp
, hostname
, targ
, mode
->m_mode
);
526 peeraddr
.sin_port
= port
;
527 tftp_sendfile(fd
, targ
, mode
->m_mode
);
530 /* this assumes the target is a directory */
531 /* on a remote unix system. hmmmm. */
532 cp
= strchr(targ
, '\0');
534 for (n
= 1; n
< argc
- 1; n
++) {
535 strcpy(cp
, tail(argv
[n
]));
536 fd
= open(argv
[n
], O_RDONLY
|mode
->m_openflags
);
538 fprintf(stderr
, "tftp: "); perror(argv
[n
]);
542 printf("putting %s to %s:%s [%s]\n",
543 argv
[n
], hostname
, targ
, mode
->m_mode
);
544 peeraddr
.sin_port
= port
;
545 tftp_sendfile(fd
, targ
, mode
->m_mode
);
552 printf("usage: %s file ... host:target, or\n", s
);
553 printf(" %s file ... target (when already connected)\n", s
);
560 get(int argc
, char *argv
[])
568 getmoreargs("get ", "(files) ");
578 for (n
= 1; n
< argc
; n
++)
579 if (strchr(argv
[n
], ':') == 0) {
584 for (n
= 1; n
< argc
; n
++) {
585 src
= strchr(argv
[n
], ':');
592 hp
= gethostbyname(argv
[n
]);
594 fprintf(stderr
, "tftp: %s: ", argv
[n
]);
595 herror((char *)NULL
);
598 bcopy(hp
->h_addr
, (caddr_t
)&peeraddr
.sin_addr
,
600 peeraddr
.sin_family
= hp
->h_addrtype
;
602 hostname
= xstrdup(hp
->h_name
);
605 cp
= argc
== 3 ? argv
[2] : tail(src
);
606 fd
= open(cp
, O_WRONLY
|O_CREAT
|O_TRUNC
|mode
->m_openflags
, 0666);
608 fprintf(stderr
, "tftp: "); perror(cp
);
612 printf("getting from %s:%s to %s [%s]\n",
613 hostname
, src
, cp
, mode
->m_mode
);
614 peeraddr
.sin_port
= port
;
615 tftp_recvfile(fd
, src
, mode
->m_mode
);
618 cp
= tail(src
); /* new .. jdg */
619 fd
= open(cp
, O_WRONLY
|O_CREAT
|O_TRUNC
|mode
->m_openflags
, 0666);
621 fprintf(stderr
, "tftp: "); perror(cp
);
625 printf("getting from %s:%s to %s [%s]\n",
626 hostname
, src
, cp
, mode
->m_mode
);
627 peeraddr
.sin_port
= port
;
628 tftp_recvfile(fd
, src
, mode
->m_mode
);
635 printf("usage: %s host:file host:file ... file, or\n", s
);
636 printf(" %s file file ... file if connected\n", s
);
639 int rexmtval
= TIMEOUT
;
642 setrexmt(int argc
, char *argv
[])
647 getmoreargs("rexmt-timeout ", "(value) ");
653 printf("usage: %s value\n", argv
[0]);
658 printf("%s: bad value\n", argv
[1]);
663 int maxtimeout
= 5 * TIMEOUT
;
666 settimeout(int argc
, char *argv
[])
671 getmoreargs("maximum-timeout ", "(value) ");
677 printf("usage: %s value\n", argv
[0]);
682 printf("%s: bad value\n", argv
[1]);
688 status(int argc
, char *argv
[])
690 (void)argc
; (void)argv
; /* Quiet unused warning */
692 printf("Connected to %s.\n", hostname
);
694 printf("Not connected.\n");
695 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
->m_mode
,
696 verbose
? "on" : "off", trace
? "on" : "off");
697 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
698 rexmtval
, maxtimeout
);
704 (void)sig
; /* Quiet unused warning */
706 bsd_signal(SIGALRM
, SIG_IGN
);
708 siglongjmp(toplevel
, -1);
717 s
= strrchr(filename
, '/');
739 line
= readline(prompt
);
743 fputs(prompt
, stdout
);
744 if (fgets(line
, LBUFLEN
, stdin
) == 0) {
752 if ((line
[0] == 0) || (line
[0] == '\n'))
755 #ifdef HAVE_READLINE_HISTORY_H
763 c
= getcmd(margv
[0]);
764 if (c
== (struct cmd
*)-1) {
765 printf("?Ambiguous command\n");
769 printf("?Invalid command\n");
772 (*c
->handler
)(margc
, margv
);
781 struct cmd
*c
, *found
;
782 int nmatches
, longest
;
787 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
788 for (q
= name
; *q
== *p
++; q
++)
789 if (*q
== 0) /* exact match? */
791 if (!*q
) { /* the name was a prefix */
792 if (q
- name
> longest
) {
796 } else if (q
- name
== longest
)
801 return ((struct cmd
*)-1);
806 * Slice a string up into argc/argv.
815 for (cp
= line
; *cp
;) {
822 while (*cp
!= '\0' && !isspace(*cp
))
832 quit(int argc
, char *argv
[])
834 (void)argc
; (void)argv
; /* Quiet unused warning */
842 help(int argc
, char *argv
[])
846 printf("%s\n", VERSION
);
849 printf("Commands may be abbreviated. Commands are:\n\n");
850 for (c
= cmdtab
; c
->name
; c
++)
851 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
858 if (c
== (struct cmd
*)-1)
859 printf("?Ambiguous help command %s\n", arg
);
860 else if (c
== (struct cmd
*)0)
861 printf("?Invalid help command %s\n", arg
);
863 printf("%s\n", c
->help
);
868 settrace(int argc
, char *argv
[])
870 (void)argc
; (void)argv
; /* Quiet unused warning */
873 printf("Packet tracing %s.\n", trace
? "on" : "off");
877 setverbose(int argc
, char *argv
[])
879 (void)argc
; (void)argv
; /* Quiet unused warning */
882 printf("Verbose mode %s.\n", verbose
? "on" : "off");