2 * Copyright (c) 1983 Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
21 All rights reserved.\n";
25 static char sccsid
[] = "@(#)main.c 5.8 (Berkeley) 10/11/88";
28 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
31 * TFTP User Program -- Command Interface.
33 #include <sys/types.h>
34 #include <sys/socket.h>
37 #include <netinet/in.h>
46 #define TIMEOUT 5 /* secs between rexmt's */
48 struct sockaddr_in sin
;
58 char *prompt
= "tftp";
65 int quit(), help(), setverbose(), settrace(), status();
66 int get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
67 int setbinary(), setascii(), setblocksize();
69 #define HELPINDENT (sizeof("connect"))
77 char vhelp
[] = "toggle verbose mode";
78 char thelp
[] = "toggle packet tracing";
79 char chelp
[] = "connect to remote tftp";
80 char qhelp
[] = "exit tftp";
81 char hhelp
[] = "print help information";
82 char shelp
[] = "send file";
83 char rhelp
[] = "receive file";
84 char mhelp
[] = "set file transfer mode";
85 char sthelp
[] = "show current status";
86 char xhelp
[] = "set per-packet retransmission timeout";
87 char ihelp
[] = "set total retransmission timeout";
88 char ashelp
[] = "set mode to netascii";
89 char bnhelp
[] = "set mode to octet";
90 char bshelp
[] = "set blocksize for next transfer";
92 struct cmd cmdtab
[] = {
93 { "connect", chelp
, setpeer
},
94 { "mode", mhelp
, modecmd
},
95 { "put", shelp
, put
},
96 { "get", rhelp
, get
},
97 { "quit", qhelp
, quit
},
98 { "verbose", vhelp
, setverbose
},
99 { "trace", thelp
, settrace
},
100 { "status", sthelp
, status
},
101 { "binary", bnhelp
, setbinary
},
102 { "ascii", ashelp
, setascii
},
103 { "rexmt", xhelp
, setrexmt
},
104 { "timeout", ihelp
, settimeout
},
105 { "blocksize", bshelp
, setblocksize
},
106 { "?", hhelp
, help
},
110 struct cmd
*getcmd();
118 struct sockaddr_in sin
;
121 sp
= getservbyname("tftp", "udp");
123 fprintf(stderr
, "tftp: udp/tftp: unknown service\n");
126 f
= socket(AF_INET
, SOCK_DGRAM
, 0);
128 perror("tftp: socket");
131 bzero((char *)&sin
, sizeof (sin
));
132 sin
.sin_family
= AF_INET
;
133 if (bind(f
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
134 perror("tftp: bind");
137 strcpy(mode
, "netascii");
138 signal(SIGINT
, intr
);
140 if (setjmp(toplevel
) != 0)
144 top
= setjmp(toplevel
) == 0;
155 struct hostent
*host
;
158 strcpy(line
, "Connect ");
160 fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
) - 1, stdin
);
166 printf("usage: %s host-name [port]\n", argv
[0]);
169 host
= gethostbyname(argv
[1]);
171 sin
.sin_family
= host
->h_addrtype
;
172 bcopy(host
->h_addr
, &sin
.sin_addr
, host
->h_length
);
173 strcpy(hostname
, host
->h_name
);
175 sin
.sin_family
= AF_INET
;
176 sin
.sin_addr
.s_addr
= inet_addr(argv
[1]);
177 if (sin
.sin_addr
.s_addr
== -1) {
179 printf("%s: unknown host\n", argv
[1]);
182 strcpy(hostname
, argv
[1]);
186 port
= atoi(argv
[2]);
188 printf("%s: bad port number\n", argv
[2]);
201 { "ascii", "netascii" },
202 { "netascii", "netascii" },
203 { "binary", "octet" },
204 { "image", "octet" },
205 { "octet", "octet" },
206 /* { "mail", "mail" }, */
213 register struct modes
*p
;
217 printf("Using %s mode to transfer files.\n", mode
);
221 for (p
= modes
; p
->m_name
; p
++)
222 if (strcmp(argv
[1], p
->m_name
) == 0)
228 printf("%s: unknown mode\n", argv
[1]);
229 /* drop through and print usage message */
232 printf("usage: %s [", argv
[0]);
234 for (p
= modes
; p
->m_name
; p
++) {
235 printf("%s%s", sep
, p
->m_name
);
243 setbinary(argc
, argv
)
250 { setmode("netascii");
256 strcpy(mode
, newmode
);
258 printf("mode set to %s\n", mode
);
270 register char *cp
, *targ
;
273 strcpy(line
, "send ");
275 fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
) - 1, stdin
);
284 targ
= argv
[argc
- 1];
285 if (index(argv
[argc
- 1], ':')) {
289 for (n
= 1; n
< argc
- 1; n
++)
290 if (index(argv
[n
], ':')) {
295 targ
= index(cp
, ':');
297 hp
= gethostbyname(cp
);
299 fprintf(stderr
, "tftp: %s: ", cp
);
300 herror((char *)NULL
);
303 bcopy(hp
->h_addr
, (caddr_t
)&sin
.sin_addr
, hp
->h_length
);
304 sin
.sin_family
= hp
->h_addrtype
;
306 strcpy(hostname
, hp
->h_name
);
309 printf("No target machine specified.\n");
313 cp
= argc
== 2 ? tail(targ
) : argv
[1];
314 fd
= open(cp
, O_RDONLY
);
316 fprintf(stderr
, "tftp: "); perror(cp
);
320 printf("putting %s to %s:%s [%s]\n",
321 cp
, hostname
, targ
, mode
);
323 sendfile(fd
, targ
, mode
);
326 /* this assumes the target is a directory */
327 /* on a remote unix system. hmmmm. */
328 cp
= index(targ
, '\0');
330 for (n
= 1; n
< argc
- 1; n
++) {
331 strcpy(cp
, tail(argv
[n
]));
332 fd
= open(argv
[n
], O_RDONLY
);
334 fprintf(stderr
, "tftp: "); perror(argv
[n
]);
338 printf("putting %s to %s:%s [%s]\n",
339 argv
[n
], hostname
, targ
, mode
);
341 sendfile(fd
, targ
, mode
);
348 printf("usage: %s file ... host:target, or\n", s
);
349 printf(" %s file ... target (when already connected)\n", s
);
364 strcpy(line
, "get ");
366 fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
) - 1, stdin
);
376 for (n
= 1; n
< argc
; n
++)
377 if (index(argv
[n
], ':') == 0) {
382 for (n
= 1; n
< argc
; n
++) {
383 src
= index(argv
[n
], ':');
390 hp
= gethostbyname(argv
[n
]);
392 fprintf(stderr
, "tftp: %s: ", argv
[n
]);
393 herror((char *)NULL
);
396 bcopy(hp
->h_addr
, (caddr_t
)&sin
.sin_addr
, hp
->h_length
);
397 sin
.sin_family
= hp
->h_addrtype
;
399 strcpy(hostname
, hp
->h_name
);
402 cp
= argc
== 3 ? argv
[2] : tail(src
);
403 fd
= creat(cp
, 0644);
405 fprintf(stderr
, "tftp: "); perror(cp
);
409 printf("getting from %s:%s to %s [%s]\n",
410 hostname
, src
, cp
, mode
);
412 recvfile(fd
, src
, mode
);
415 cp
= tail(src
); /* new .. jdg */
416 fd
= creat(cp
, 0644);
418 fprintf(stderr
, "tftp: "); perror(cp
);
422 printf("getting from %s:%s to %s [%s]\n",
423 hostname
, src
, cp
, mode
);
425 recvfile(fd
, src
, mode
);
432 printf("usage: %s host:file host:file ... file, or\n", s
);
433 printf(" %s file file ... file if connected\n", s
);
436 int rexmtval
= TIMEOUT
;
444 strcpy(line
, "Rexmt-timeout ");
446 fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
) - 1, stdin
);
452 printf("usage: %s value\n", argv
[0]);
457 printf("%d: bad value\n", t
);
462 int maxtimeout
= 5 * TIMEOUT
;
464 settimeout(argc
, argv
)
470 strcpy(line
, "Maximum-timeout ");
472 fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
) - 1, stdin
);
478 printf("usage: %s value\n", argv
[0]);
483 printf("%d: bad value\n", t
);
492 printf("Connected to %s.\n", hostname
);
494 printf("Not connected.\n");
495 printf("Mode: %s Verbose: %s Tracing: %s\n", mode
,
496 verbose
? "on" : "off", trace
? "on" : "off");
497 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
498 rexmtval
, maxtimeout
);
503 signal(SIGALRM
, SIG_IGN
);
505 longjmp(toplevel
, -1);
515 s
= rindex(filename
, '/');
531 register struct cmd
*c
;
536 printf("%s> ", prompt
);
537 if (fgets(line
, sizeof(line
), stdin
) == 0) {
547 c
= getcmd(margv
[0]);
548 if (c
== (struct cmd
*)-1) {
549 printf("?Ambiguous command\n");
553 printf("?Invalid command\n");
556 (*c
->handler
)(margc
, margv
);
564 register char *p
, *q
;
565 register struct cmd
*c
, *found
;
566 register int nmatches
, longest
;
571 for (c
= cmdtab
; p
= c
->name
; c
++) {
572 for (q
= name
; *q
== *p
++; q
++)
573 if (*q
== 0) /* exact match? */
575 if (!*q
) { /* the name was a prefix */
576 if (q
- name
> longest
) {
580 } else if (q
- name
== longest
)
585 return ((struct cmd
*)-1);
590 * Slice a string up into argc/argv.
595 register char **argp
= margv
;
598 for (cp
= line
; *cp
;) {
605 while (*cp
!= '\0' && !isspace(*cp
))
627 register struct cmd
*c
;
630 printf("Commands may be abbreviated. Commands are:\n\n");
631 for (c
= cmdtab
; c
->name
; c
++)
632 printf("%-*s\t%s\n", HELPINDENT
, c
->name
, c
->help
);
639 if (c
== (struct cmd
*)-1)
640 printf("?Ambiguous help command %s\n", arg
);
641 else if (c
== (struct cmd
*)0)
642 printf("?Invalid help command %s\n", arg
);
644 printf("%s\n", c
->help
);
652 printf("Packet tracing %s.\n", trace
? "on" : "off");
659 printf("Verbose mode %s.\n", verbose
? "on" : "off");
662 setblocksize(argc
, argv
)
668 strcpy(line
, "blocksize ");
670 fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
) - 1, stdin
);
676 printf("usage: %s value\n", argv
[0]);
680 if (t
< 8 || t
> 1432)
681 printf("%d: bad value\n", t
);