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 *);
187 main(int argc
, char *argv
[])
189 struct sockaddr_in s_in
;
194 while ((c
= getopt(argc
, argv
, "Vv")) != -1) {
200 /* Print version and configuration to stdout and exit */
201 printf("%s\n", TFTP_CONFIG_STR
);
204 fprintf(stderr
, "Usage: %s [-v] [host]\n", argv
[0]);
209 pargc
= argc
- (optind
-1);
210 pargv
= argv
+ (optind
-1);
212 sp
= getservbyname("tftp", "udp");
214 /* Use canned values */
215 fprintf(stderr
, "tftp: tftp/udp: unknown service, faking it...\n");
216 sp
= xmalloc(sizeof(struct servent
));
217 sp
->s_name
= (char *)"tftp";
218 sp
->s_aliases
= NULL
;
219 sp
->s_port
= htons(IPPORT_TFTP
);
220 sp
->s_proto
= (char *)"udp";
223 f
= socket(AF_INET
, SOCK_DGRAM
, 0);
225 perror("tftp: socket");
228 bzero((char *)&s_in
, sizeof (s_in
));
229 s_in
.sin_family
= AF_INET
;
230 if (bind(f
, (struct sockaddr
*)&s_in
, sizeof (s_in
)) < 0) {
231 perror("tftp: bind");
235 bsd_signal(SIGINT
, intr
);
237 if (sigsetjmp(toplevel
,1) != 0)
239 setpeer(pargc
, pargv
);
241 if (sigsetjmp(toplevel
,1) != 0)
245 #ifdef HAVE_READLINE_HISTORY_H
252 return 0; /* Never reached */
257 /* Called when a command is incomplete; modifies
258 the global variable "line" */
260 getmoreargs(const char *partial
, const char *mprompt
)
266 len
= strlen(partial
);
267 eline
= readline(mprompt
);
271 elen
= strlen(eline
);
275 line
= xmalloc(len
+elen
+1);
276 strcpy(line
, partial
);
277 strcpy(line
+len
, eline
);
280 #ifdef HAVE_READLINE_HISTORY_H
284 int len
= strlen(partial
);
286 strcpy(line
, partial
);
287 fputs(mprompt
, stdout
);
288 if ( fgets(line
+len
, LBUFLEN
-len
, stdin
) == 0 )
295 setpeer(int argc
, char *argv
[])
297 struct hostent
*host
;
300 getmoreargs("connect ", "(to) ");
305 if ((argc
< 2) || (argc
> 3)) {
306 printf("usage: %s host-name [port]\n", argv
[0]);
310 host
= gethostbyname(argv
[1]);
313 printf("%s: unknown host\n", argv
[1]);
316 peeraddr
.sin_family
= host
->h_addrtype
;
317 bcopy(host
->h_addr
, &peeraddr
.sin_addr
, host
->h_length
);
318 hostname
= xstrdup(host
->h_name
);
323 usp
= getservbyname(argv
[2], "udp");
327 unsigned long myport
;
329 myport
= strtoul(argv
[2], &ep
, 10);
330 if (*ep
|| myport
> 65535UL) {
331 printf("%s: bad port number\n", argv
[2]);
335 port
= htons((u_short
)myport
);
340 printf("Connected to %s (%s), port %u\n",
341 hostname
, inet_ntoa(peeraddr
.sin_addr
),
342 (unsigned int)ntohs(port
));
348 modecmd(int argc
, char *argv
[])
350 const struct modes
*p
;
354 printf("Using %s mode to transfer files.\n", mode
->m_mode
);
358 for (p
= modes
; p
->m_name
; p
++)
359 if (strcmp(argv
[1], p
->m_name
) == 0)
365 printf("%s: unknown mode\n", argv
[1]);
366 /* drop through and print usage message */
369 printf("usage: %s [", argv
[0]);
371 for (p
= modes
; p
->m_name
; p
++) {
372 printf("%s%s", sep
, p
->m_name
);
381 setbinary(int argc
, char *argv
[])
383 (void)argc
; (void)argv
; /* Quiet unused warning */
384 settftpmode(MODE_OCTET
);
388 setascii(int argc
, char *argv
[])
390 (void)argc
; (void)argv
; /* Quiet unused warning */
391 settftpmode(MODE_NETASCII
);
395 settftpmode(const struct modes
*newmode
)
399 printf("mode set to %s\n", mode
->m_mode
);
407 put(int argc
, char *argv
[])
414 getmoreargs("send ", "(file) ");
423 targ
= argv
[argc
- 1];
424 if (strchr(argv
[argc
- 1], ':')) {
427 for (n
= 1; n
< argc
- 1; n
++)
428 if (strchr(argv
[n
], ':')) {
433 targ
= strchr(cp
, ':');
435 hp
= gethostbyname(cp
);
437 fprintf(stderr
, "tftp: %s: ", cp
);
438 herror((char *)NULL
);
441 bcopy(hp
->h_addr
, (caddr_t
)&peeraddr
.sin_addr
, hp
->h_length
);
442 peeraddr
.sin_family
= hp
->h_addrtype
;
444 hostname
= xstrdup(hp
->h_name
);
447 printf("No target machine specified.\n");
451 cp
= argc
== 2 ? tail(targ
) : argv
[1];
452 fd
= open(cp
, O_RDONLY
|mode
->m_openflags
);
454 fprintf(stderr
, "tftp: "); perror(cp
);
458 printf("putting %s to %s:%s [%s]\n",
459 cp
, hostname
, targ
, mode
->m_mode
);
460 peeraddr
.sin_port
= port
;
461 tftp_sendfile(fd
, targ
, mode
->m_mode
);
464 /* this assumes the target is a directory */
465 /* on a remote unix system. hmmmm. */
466 cp
= strchr(targ
, '\0');
468 for (n
= 1; n
< argc
- 1; n
++) {
469 strcpy(cp
, tail(argv
[n
]));
470 fd
= open(argv
[n
], O_RDONLY
|mode
->m_openflags
);
472 fprintf(stderr
, "tftp: "); perror(argv
[n
]);
476 printf("putting %s to %s:%s [%s]\n",
477 argv
[n
], hostname
, targ
, mode
->m_mode
);
478 peeraddr
.sin_port
= port
;
479 tftp_sendfile(fd
, targ
, mode
->m_mode
);
486 printf("usage: %s file ... host:target, or\n", s
);
487 printf(" %s file ... target (when already connected)\n", s
);
494 get(int argc
, char *argv
[])
502 getmoreargs("get ", "(files) ");
512 for (n
= 1; n
< argc
; n
++)
513 if (strchr(argv
[n
], ':') == 0) {
518 for (n
= 1; n
< argc
; n
++) {
519 src
= strchr(argv
[n
], ':');
526 hp
= gethostbyname(argv
[n
]);
528 fprintf(stderr
, "tftp: %s: ", argv
[n
]);
529 herror((char *)NULL
);
532 bcopy(hp
->h_addr
, (caddr_t
)&peeraddr
.sin_addr
,
534 peeraddr
.sin_family
= hp
->h_addrtype
;
536 hostname
= xstrdup(hp
->h_name
);
539 cp
= argc
== 3 ? argv
[2] : tail(src
);
540 fd
= open(cp
, O_WRONLY
|O_CREAT
|O_TRUNC
|mode
->m_openflags
, 0666);
542 fprintf(stderr
, "tftp: "); perror(cp
);
546 printf("getting from %s:%s to %s [%s]\n",
547 hostname
, src
, cp
, mode
->m_mode
);
548 peeraddr
.sin_port
= port
;
549 tftp_recvfile(fd
, src
, mode
->m_mode
);
552 cp
= tail(src
); /* new .. jdg */
553 fd
= open(cp
, O_WRONLY
|O_CREAT
|O_TRUNC
|mode
->m_openflags
, 0666);
555 fprintf(stderr
, "tftp: "); perror(cp
);
559 printf("getting from %s:%s to %s [%s]\n",
560 hostname
, src
, cp
, mode
->m_mode
);
561 peeraddr
.sin_port
= port
;
562 tftp_recvfile(fd
, src
, mode
->m_mode
);
569 printf("usage: %s host:file host:file ... file, or\n", s
);
570 printf(" %s file file ... file if connected\n", s
);
573 int rexmtval
= TIMEOUT
;
576 setrexmt(int argc
, char *argv
[])
581 getmoreargs("rexmt-timeout ", "(value) ");
587 printf("usage: %s value\n", argv
[0]);
592 printf("%s: bad value\n", argv
[1]);
597 int maxtimeout
= 5 * TIMEOUT
;
600 settimeout(int argc
, char *argv
[])
605 getmoreargs("maximum-timeout ", "(value) ");
611 printf("usage: %s value\n", argv
[0]);
616 printf("%s: bad value\n", argv
[1]);
622 status(int argc
, char *argv
[])
624 (void)argc
; (void)argv
; /* Quiet unused warning */
626 printf("Connected to %s.\n", hostname
);
628 printf("Not connected.\n");
629 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
->m_mode
,
630 verbose
? "on" : "off", trace
? "on" : "off");
631 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
632 rexmtval
, maxtimeout
);
638 (void)sig
; /* Quiet unused warning */
640 bsd_signal(SIGALRM
, SIG_IGN
);
642 siglongjmp(toplevel
, -1);
651 s
= strrchr(filename
, '/');
673 line
= readline(prompt
);
677 fputs(prompt
, stdout
);
678 if (fgets(line
, LBUFLEN
, stdin
) == 0) {
686 if ((line
[0] == 0) || (line
[0] == '\n'))
689 #ifdef HAVE_READLINE_HISTORY_H
697 c
= getcmd(margv
[0]);
698 if (c
== (struct cmd
*)-1) {
699 printf("?Ambiguous command\n");
703 printf("?Invalid command\n");
706 (*c
->handler
)(margc
, margv
);
715 struct cmd
*c
, *found
;
716 int nmatches
, longest
;
721 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
722 for (q
= name
; *q
== *p
++; q
++)
723 if (*q
== 0) /* exact match? */
725 if (!*q
) { /* the name was a prefix */
726 if (q
- name
> longest
) {
730 } else if (q
- name
== longest
)
735 return ((struct cmd
*)-1);
740 * Slice a string up into argc/argv.
749 for (cp
= line
; *cp
;) {
756 while (*cp
!= '\0' && !isspace(*cp
))
766 quit(int argc
, char *argv
[])
768 (void)argc
; (void)argv
; /* Quiet unused warning */
776 help(int argc
, char *argv
[])
780 printf("%s\n", VERSION
);
783 printf("Commands may be abbreviated. Commands are:\n\n");
784 for (c
= cmdtab
; c
->name
; c
++)
785 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
792 if (c
== (struct cmd
*)-1)
793 printf("?Ambiguous help command %s\n", arg
);
794 else if (c
== (struct cmd
*)0)
795 printf("?Invalid help command %s\n", arg
);
797 printf("%s\n", c
->help
);
802 settrace(int argc
, char *argv
[])
804 (void)argc
; (void)argv
; /* Quiet unused warning */
807 printf("Packet tracing %s.\n", trace
? "on" : "off");
811 setverbose(int argc
, char *argv
[])
813 (void)argc
; (void)argv
; /* Quiet unused warning */
816 printf("Verbose mode %s.\n", verbose
? "on" : "off");