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.
54 #include <sys/types.h>
55 #include <sys/socket.h>
58 #include <netinet/in.h>
60 #include <arpa/inet.h>
73 #include <readline/readline.h>
74 #ifdef HAVE_READLINE_HISTORY_H
75 #include <readline/history.h>
81 #define TIMEOUT 5 /* secs between rexmt's */
82 #define LBUFLEN 200 /* size of input buffer */
84 struct sockaddr_in peeraddr
;
98 const char *prompt
= "tftp> ";
103 void get (int, char **);
104 void help (int, char **);
105 void modecmd (int, char **);
106 void put (int, char **);
107 void quit (int, char **);
108 void setascii (int, char **);
109 void setbinary (int, char **);
110 void setpeer (int, char **);
111 void setrexmt (int, char **);
112 void settimeout (int, char **);
113 void settrace (int, char **);
114 void setverbose (int, char **);
115 void status (int, char **);
117 static void command (void);
119 static void getusage (char *);
120 static void makeargv (void);
121 static void putusage (char *);
122 static void settftpmode (const char *);
124 #define HELPINDENT (sizeof("connect"))
129 void (*handler
) (int, char **);
132 struct cmd cmdtab
[] = {
134 "connect to remote tftp",
137 "set file transfer mode",
149 "toggle verbose mode",
152 "toggle packet tracing",
155 "show current status",
161 "set mode to netascii",
164 "set per-packet transmission timeout",
167 "set total retransmission timeout",
170 "print help information",
173 "print help information",
178 struct cmd
*getcmd(char *);
181 char *xstrdup(const char *);
184 main(int argc
, char *argv
[])
186 struct sockaddr_in s_in
;
191 while ((c
= getopt(argc
, argv
, "Vv")) != -1) {
197 /* Print version and configuration to stdout and exit */
198 printf("%s\n", TFTP_CONFIG_STR
);
201 fprintf(stderr
, "Usage: %s [-v] [host]\n", argv
[0]);
206 pargc
= argc
- (optind
-1);
207 pargv
= argv
+ (optind
-1);
209 sp
= getservbyname("tftp", "udp");
211 /* Use canned values */
212 fprintf(stderr
, "tftp: tftp/udp: unknown service, faking it...\n");
213 sp
= xmalloc(sizeof(struct servent
));
214 sp
->s_name
= (char *)"tftp";
215 sp
->s_aliases
= NULL
;
216 sp
->s_port
= htons(IPPORT_TFTP
);
217 sp
->s_proto
= (char *)"udp";
220 f
= socket(AF_INET
, SOCK_DGRAM
, 0);
222 perror("tftp: socket");
225 bzero((char *)&s_in
, sizeof (s_in
));
226 s_in
.sin_family
= AF_INET
;
227 if (bind(f
, (struct sockaddr
*)&s_in
, sizeof (s_in
)) < 0) {
228 perror("tftp: bind");
231 strcpy(mode
, "netascii");
232 bsd_signal(SIGINT
, intr
);
234 if (sigsetjmp(toplevel
,1) != 0)
236 setpeer(pargc
, pargv
);
238 if (sigsetjmp(toplevel
,1) != 0)
242 #ifdef HAVE_READLINE_HISTORY_H
249 return 0; /* Never reached */
254 /* Called when a command is incomplete; modifies
255 the global variable "line" */
257 getmoreargs(const char *partial
, const char *mprompt
)
263 len
= strlen(partial
);
264 eline
= readline(mprompt
);
268 elen
= strlen(eline
);
272 line
= xmalloc(len
+elen
+1);
273 strcpy(line
, partial
);
274 strcpy(line
+len
, eline
);
277 #ifdef HAVE_READLINE_HISTORY_H
281 int len
= strlen(partial
);
283 strcpy(line
, partial
);
284 fputs(mprompt
, stdout
);
285 if ( fgets(line
+len
, LBUFLEN
-len
, stdin
) == 0 )
292 setpeer(int argc
, char *argv
[])
294 struct hostent
*host
;
297 getmoreargs("connect ", "(to) ");
302 if ((argc
< 2) || (argc
> 3)) {
303 printf("usage: %s host-name [port]\n", argv
[0]);
307 host
= gethostbyname(argv
[1]);
310 printf("%s: unknown host\n", argv
[1]);
313 peeraddr
.sin_family
= host
->h_addrtype
;
314 bcopy(host
->h_addr
, &peeraddr
.sin_addr
, host
->h_length
);
315 hostname
= xstrdup(host
->h_name
);
320 usp
= getservbyname(argv
[2], "udp");
324 unsigned long myport
;
326 myport
= strtoul(argv
[2], &ep
, 10);
327 if (*ep
|| myport
> 65535UL) {
328 printf("%s: bad port number\n", argv
[2]);
332 port
= htons((u_short
)myport
);
337 printf("Connected to %s (%s), port %u\n",
338 hostname
, inet_ntoa(peeraddr
.sin_addr
),
339 (unsigned int)ntohs(port
));
348 { "ascii", "netascii" },
349 { "netascii", "netascii" },
350 { "binary", "octet" },
351 { "image", "octet" },
352 { "octet", "octet" },
353 /* { "mail", "mail" }, */
358 modecmd(int argc
, char *argv
[])
364 printf("Using %s mode to transfer files.\n", mode
);
368 for (p
= modes
; p
->m_name
; p
++)
369 if (strcmp(argv
[1], p
->m_name
) == 0)
372 settftpmode(p
->m_mode
);
375 printf("%s: unknown mode\n", argv
[1]);
376 /* drop through and print usage message */
379 printf("usage: %s [", argv
[0]);
381 for (p
= modes
; p
->m_name
; p
++) {
382 printf("%s%s", sep
, p
->m_name
);
391 setbinary(int argc
, char *argv
[])
393 (void)argc
; (void)argv
; /* Quiet unused warning */
394 settftpmode("octet");
398 setascii(int argc
, char *argv
[])
400 (void)argc
; (void)argv
; /* Quiet unused warning */
401 settftpmode("netascii");
405 settftpmode(const char *newmode
)
407 strcpy(mode
, newmode
);
409 printf("mode set to %s\n", mode
);
417 put(int argc
, char *argv
[])
424 getmoreargs("send ", "(file) ");
433 targ
= argv
[argc
- 1];
434 if (strchr(argv
[argc
- 1], ':')) {
437 for (n
= 1; n
< argc
- 1; n
++)
438 if (strchr(argv
[n
], ':')) {
443 targ
= strchr(cp
, ':');
445 hp
= gethostbyname(cp
);
447 fprintf(stderr
, "tftp: %s: ", cp
);
448 herror((char *)NULL
);
451 bcopy(hp
->h_addr
, (caddr_t
)&peeraddr
.sin_addr
, hp
->h_length
);
452 peeraddr
.sin_family
= hp
->h_addrtype
;
454 hostname
= xstrdup(hp
->h_name
);
457 printf("No target machine specified.\n");
461 cp
= argc
== 2 ? tail(targ
) : argv
[1];
462 fd
= open(cp
, O_RDONLY
);
464 fprintf(stderr
, "tftp: "); perror(cp
);
468 printf("putting %s to %s:%s [%s]\n",
469 cp
, hostname
, targ
, mode
);
470 peeraddr
.sin_port
= port
;
471 tftp_sendfile(fd
, targ
, mode
);
474 /* this assumes the target is a directory */
475 /* on a remote unix system. hmmmm. */
476 cp
= strchr(targ
, '\0');
478 for (n
= 1; n
< argc
- 1; n
++) {
479 strcpy(cp
, tail(argv
[n
]));
480 fd
= open(argv
[n
], O_RDONLY
);
482 fprintf(stderr
, "tftp: "); perror(argv
[n
]);
486 printf("putting %s to %s:%s [%s]\n",
487 argv
[n
], hostname
, targ
, mode
);
488 peeraddr
.sin_port
= port
;
489 tftp_sendfile(fd
, targ
, mode
);
496 printf("usage: %s file ... host:target, or\n", s
);
497 printf(" %s file ... target (when already connected)\n", s
);
504 get(int argc
, char *argv
[])
512 getmoreargs("get ", "(files) ");
522 for (n
= 1; n
< argc
; n
++)
523 if (strchr(argv
[n
], ':') == 0) {
528 for (n
= 1; n
< argc
; n
++) {
529 src
= strchr(argv
[n
], ':');
536 hp
= gethostbyname(argv
[n
]);
538 fprintf(stderr
, "tftp: %s: ", argv
[n
]);
539 herror((char *)NULL
);
542 bcopy(hp
->h_addr
, (caddr_t
)&peeraddr
.sin_addr
,
544 peeraddr
.sin_family
= hp
->h_addrtype
;
546 hostname
= xstrdup(hp
->h_name
);
549 cp
= argc
== 3 ? argv
[2] : tail(src
);
550 fd
= creat(cp
, 0644);
552 fprintf(stderr
, "tftp: "); perror(cp
);
556 printf("getting from %s:%s to %s [%s]\n",
557 hostname
, src
, cp
, mode
);
558 peeraddr
.sin_port
= port
;
559 tftp_recvfile(fd
, src
, mode
);
562 cp
= tail(src
); /* new .. jdg */
563 fd
= creat(cp
, 0644);
565 fprintf(stderr
, "tftp: "); perror(cp
);
569 printf("getting from %s:%s to %s [%s]\n",
570 hostname
, src
, cp
, mode
);
571 peeraddr
.sin_port
= port
;
572 tftp_recvfile(fd
, src
, mode
);
579 printf("usage: %s host:file host:file ... file, or\n", s
);
580 printf(" %s file file ... file if connected\n", s
);
583 int rexmtval
= TIMEOUT
;
586 setrexmt(int argc
, char *argv
[])
591 getmoreargs("rexmt-timeout ", "(value) ");
597 printf("usage: %s value\n", argv
[0]);
602 printf("%s: bad value\n", argv
[1]);
607 int maxtimeout
= 5 * TIMEOUT
;
610 settimeout(int argc
, char *argv
[])
615 getmoreargs("maximum-timeout ", "(value) ");
621 printf("usage: %s value\n", argv
[0]);
626 printf("%s: bad value\n", argv
[1]);
632 status(int argc
, char *argv
[])
634 (void)argc
; (void)argv
; /* Quiet unused warning */
636 printf("Connected to %s.\n", hostname
);
638 printf("Not connected.\n");
639 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
,
640 verbose
? "on" : "off", trace
? "on" : "off");
641 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
642 rexmtval
, maxtimeout
);
648 (void)sig
; /* Quiet unused warning */
650 bsd_signal(SIGALRM
, SIG_IGN
);
652 siglongjmp(toplevel
, -1);
661 s
= strrchr(filename
, '/');
683 line
= readline(prompt
);
687 fputs(prompt
, stdout
);
688 if (fgets(line
, LBUFLEN
, stdin
) == 0) {
696 if ((line
[0] == 0) || (line
[0] == '\n'))
699 #ifdef HAVE_READLINE_HISTORY_H
707 c
= getcmd(margv
[0]);
708 if (c
== (struct cmd
*)-1) {
709 printf("?Ambiguous command\n");
713 printf("?Invalid command\n");
716 (*c
->handler
)(margc
, margv
);
725 struct cmd
*c
, *found
;
726 int nmatches
, longest
;
731 for (c
= cmdtab
; (p
= c
->name
) != NULL
; c
++) {
732 for (q
= name
; *q
== *p
++; q
++)
733 if (*q
== 0) /* exact match? */
735 if (!*q
) { /* the name was a prefix */
736 if (q
- name
> longest
) {
740 } else if (q
- name
== longest
)
745 return ((struct cmd
*)-1);
750 * Slice a string up into argc/argv.
759 for (cp
= line
; *cp
;) {
766 while (*cp
!= '\0' && !isspace(*cp
))
776 quit(int argc
, char *argv
[])
778 (void)argc
; (void)argv
; /* Quiet unused warning */
786 help(int argc
, char *argv
[])
790 printf("%s\n", VERSION
);
793 printf("Commands may be abbreviated. Commands are:\n\n");
794 for (c
= cmdtab
; c
->name
; c
++)
795 printf("%-*s\t%s\n", (int)HELPINDENT
, c
->name
, c
->help
);
802 if (c
== (struct cmd
*)-1)
803 printf("?Ambiguous help command %s\n", arg
);
804 else if (c
== (struct cmd
*)0)
805 printf("?Invalid help command %s\n", arg
);
807 printf("%s\n", c
->help
);
812 settrace(int argc
, char *argv
[])
814 (void)argc
; (void)argv
; /* Quiet unused warning */
817 printf("Packet tracing %s.\n", trace
? "on" : "off");
821 setverbose(int argc
, char *argv
[])
823 (void)argc
; (void)argv
; /* Quiet unused warning */
826 printf("Verbose mode %s.\n", verbose
? "on" : "off");