2 * Copyright (c) 1983 Regents of the University of California.
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
35 "@(#) Copyright (c) 1983 Regents of the University of California.\n"
36 "All rights reserved.\n";
39 * From: @(#)main.c 5.10 (Berkeley) 3/1/91
42 "$Id: main.c,v 1.9 1996/11/25 18:42:46 dholland Exp $";
44 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
47 * TFTP User Program -- Command Interface.
49 #include <sys/types.h>
50 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <netinet/ip.h>
55 #include <arpa/inet.h>
67 #define TIMEOUT 5 /* secs between rexmt's */
69 struct sockaddr_in s_inn;
73 int rexmtval = TIMEOUT;
74 int maxtimeout = 5 * TIMEOUT;
76 void sendfile(int fd, char *name, char *modestr);
77 void recvfile(int fd, char *name, char *modestr);
83 static char line[200];
85 static char *margv[20];
86 static const char *prompt = "tftp";
87 static struct servent *sp;
89 static void intr(int);
92 void command(int top);
93 void quit(int argc, char *argv[]);
94 void help(int argc, char *argv[]);
95 void setverbose(int argc, char *argv[]);
96 void settrace(int argc, char *argv[]);
97 void status(int argc, char *argv[]);
98 void get(int argc, char *argv[]);
99 void put(int argc, char *argv[]);
100 void setpeer(int argc, char *argv[]);
101 void modecmd(int argc, char *argv[]);
102 void setrexmt(int argc, char *argv[]);
103 void settimeout(int argc, char *argv[]);
104 void setbinary(int argc, char *argv[]);
105 void setascii(int argc, char *argv[]);
106 void setmode(const char *newmode);
107 void putusage(const char *s);
108 void getusage(const char *s);
110 #define HELPINDENT ((int) sizeof("connect"))
115 void (*handler)(int, char *[]);
118 char vhelp[] = "toggle verbose mode";
119 char thelp[] = "toggle packet tracing";
120 char chelp[] = "connect to remote tftp";
121 char qhelp[] = "exit tftp";
122 char hhelp[] = "print help information";
123 char shelp[] = "send file";
124 char rhelp[] = "receive file";
125 char mhelp[] = "set file transfer mode";
126 char sthelp[] = "show current status";
127 char xhelp[] = "set per-packet retransmission timeout";
128 char ihelp[] = "set total retransmission timeout";
129 char ashelp[] = "set mode to netascii";
130 char bnhelp[] = "set mode to octet";
132 struct cmd cmdtab[] = {
133 { "connect", chelp, setpeer },
134 { "mode", mhelp, modecmd },
135 { "put", shelp, put },
136 { "get", rhelp, get },
137 { "quit", qhelp, quit },
138 { "verbose", vhelp, setverbose },
139 { "trace", thelp, settrace },
140 { "status", sthelp, status },
141 { "binary", bnhelp, setbinary },
142 { "ascii", ashelp, setascii },
143 { "rexmt", xhelp, setrexmt },
144 { "timeout", ihelp, settimeout },
145 { "?", hhelp, help },
149 static struct cmd *getcmd(const char *name);
150 static char *tail(char *filename);
153 main(int argc, char *argv[])
155 struct sockaddr_in s_in;
158 sp = getservbyname("tftp", "udp");
160 fprintf(stderr, "tftp: udp/tftp: unknown service\n");
163 f = socket(AF_INET, SOCK_DGRAM, 0);
165 perror("tftp: socket");
168 memset(&s_in, 0, sizeof(s_in));
169 s_in.sin_family = AF_INET;
170 if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
171 perror("tftp: bind");
174 strcpy(mode, "netascii");
175 signal(SIGINT, intr);
177 if (sigsetjmp(toplevel, 1) != 0)
181 top = sigsetjmp(toplevel, 1) == 0;
186 static char hostname[100];
189 setpeer(int argc, char *argv[])
191 struct hostent *host;
194 strcpy(line, "Connect ");
196 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
202 printf("usage: %s host-name [port]\n", argv[0]);
205 host = gethostbyname(argv[1]);
207 s_inn.sin_family = host->h_addrtype;
208 if (host->h_length > (int)sizeof(s_inn.sin_addr)) {
209 host->h_length = sizeof(s_inn.sin_addr);
211 memcpy(&s_inn.sin_addr, host->h_addr, host->h_length);
212 strncpy(hostname, host->h_name, sizeof(hostname));
213 hostname[sizeof(hostname)-1] = 0;
216 s_inn.sin_family = AF_INET;
217 if (!inet_aton(argv[1], &s_inn.sin_addr)) {
219 printf("%s: unknown host\n", argv[1]);
222 strcpy(hostname, argv[1]);
226 port = atoi(argv[2]);
228 printf("%s: bad port number\n", argv[2]);
241 { "ascii", "netascii" },
242 { "netascii", "netascii" },
243 { "binary", "octet" },
244 { "image", "octet" },
245 { "octet", "octet" },
246 /* { "mail", "mail" }, */
251 modecmd(int argc, char *argv[])
253 register struct modes *p;
257 printf("Using %s mode to transfer files.\n", mode);
261 for (p = modes; p->m_name; p++)
262 if (strcmp(argv[1], p->m_name) == 0)
268 printf("%s: unknown mode\n", argv[1]);
269 /* drop through and print usage message */
272 printf("usage: %s [", argv[0]);
274 for (p = modes; p->m_name; p++) {
275 printf("%s%s", sep, p->m_name);
284 setbinary(int argc, char *argv[])
292 setascii(int argc, char *argv[])
300 setmode(const char *newmode)
302 strcpy(mode, newmode);
304 printf("mode set to %s\n", mode);
312 put(int argc, char *argv[])
316 register char *ccp, *targ;
319 strcpy(line, "send ");
321 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
330 targ = argv[argc - 1];
331 if (index(argv[argc - 1], ':')) {
335 for (n = 1; n < argc - 1; n++)
336 if (index(argv[n], ':')) {
341 targ = index(cp, ':');
343 hp = gethostbyname(cp);
345 fprintf(stderr, "tftp: %s: ", cp);
346 herror((char *)NULL);
349 if (hp->h_length > (int)sizeof(s_inn.sin_addr)) {
350 hp->h_length = sizeof(s_inn.sin_addr);
352 memcpy(&s_inn.sin_addr, hp->h_addr, hp->h_length);
353 s_inn.sin_family = hp->h_addrtype;
355 strncpy(hostname, hp->h_name, sizeof(hostname));
356 hostname[sizeof(hostname)-1] = 0;
359 printf("No target machine specified.\n");
363 ccp = argc == 2 ? tail(targ) : argv[1];
364 fd = open(ccp, O_RDONLY);
366 fprintf(stderr, "tftp: ");
371 printf("putting %s to %s:%s [%s]\n",
372 ccp, hostname, targ, mode);
373 s_inn.sin_port = port;
374 sendfile(fd, targ, mode);
377 /* this assumes the target is a directory */
378 /* on a remote unix system. hmmmm. */
379 ccp = targ+strlen(targ);
381 for (n = 1; n < argc - 1; n++) {
382 strcpy(ccp, tail(argv[n]));
383 fd = open(argv[n], O_RDONLY);
385 fprintf(stderr, "tftp: "); perror(argv[n]);
389 printf("putting %s to %s:%s [%s]\n",
390 argv[n], hostname, targ, mode);
391 s_inn.sin_port = port;
392 sendfile(fd, targ, mode);
397 putusage(const char *s)
399 printf("usage: %s file ... host:target, or\n", s);
400 printf(" %s file ... target (when already connected)\n", s);
407 get(int argc, char *argv[])
415 strcpy(line, "get ");
417 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
427 for (n = 1; n < argc ; n++)
428 if (index(argv[n], ':') == 0) {
433 for (n = 1; n < argc ; n++) {
434 src = index(argv[n], ':');
441 hp = gethostbyname(argv[n]);
443 fprintf(stderr, "tftp: %s: ", argv[n]);
447 if (hp->h_length > (int)sizeof(s_inn.sin_addr)) {
448 hp->h_length = sizeof(s_inn.sin_addr);
450 memcpy(&s_inn.sin_addr, hp->h_addr, hp->h_length);
451 s_inn.sin_family = hp->h_addrtype;
453 strncpy(hostname, hp->h_name, sizeof(hostname));
454 hostname[sizeof(hostname)-1] = 0;
457 cp = argc == 3 ? argv[2] : tail(src);
458 fd = creat(cp, 0644);
460 fprintf(stderr, "tftp: "); perror(cp);
464 printf("getting from %s:%s to %s [%s]\n",
465 hostname, src, cp, mode);
466 s_inn.sin_port = port;
467 recvfile(fd, src, mode);
470 cp = tail(src); /* new .. jdg */
471 fd = creat(cp, 0644);
473 fprintf(stderr, "tftp: "); perror(cp);
477 printf("getting from %s:%s to %s [%s]\n",
478 hostname, src, cp, mode);
479 s_inn.sin_port = port;
480 recvfile(fd, src, mode);
485 getusage(const char *s)
487 printf("usage: %s host:file host:file ... file, or\n", s);
488 printf(" %s file file ... file if connected\n", s);
493 setrexmt(int argc, char *argv[])
498 strcpy(line, "Rexmt-timeout ");
500 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
506 printf("usage: %s value\n", argv[0]);
511 printf("%s: bad value\n", argv[1]);
517 settimeout(int argc, char *argv[])
522 strcpy(line, "Maximum-timeout ");
524 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
530 printf("usage: %s value\n", argv[0]);
535 printf("%s: bad value\n", argv[1]);
541 status(int argc, char *argv[])
547 printf("Connected to %s.\n", hostname);
549 printf("Not connected.\n");
550 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
551 verbose ? "on" : "off", trace ? "on" : "off");
552 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
553 rexmtval, maxtimeout);
562 signal(SIGALRM, SIG_IGN);
564 siglongjmp(toplevel, -1);
574 s = strrchr(filename, '/');
590 register struct cmd *c;
595 printf("%s> ", prompt);
596 if (fgets(line, sizeof(line), stdin) == 0) {
606 c = getcmd(margv[0]);
607 if (c == (struct cmd *)-1) {
608 printf("?Ambiguous command\n");
612 printf("?Invalid command\n");
615 (*c->handler)(margc, margv);
620 getcmd(const char *name)
623 struct cmd *c, *found;
624 int nmatches, longest;
629 for (c = cmdtab; (p = c->name)!=NULL; c++) {
630 for (q = name; *q == *p++; q++)
631 if (*q == 0) /* exact match? */
633 if (!*q) { /* the name was a prefix */
634 if (q - name > longest) {
638 } else if (q - name == longest)
643 return ((struct cmd *)-1);
648 * Slice a string up into argc/argv.
654 register char **argp = margv;
657 for (cp = line; *cp;) {
664 while (*cp != '\0' && !isspace(*cp))
674 quit(int ign1, char *ign2[])
685 help(int argc, char *argv[])
687 register struct cmd *c;
690 printf("Commands may be abbreviated. Commands are:\n\n");
691 for (c = cmdtab; c->name; c++)
692 printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
699 if (c == (struct cmd *)-1)
700 printf("?Ambiguous help command %s\n", arg);
701 else if (c == (struct cmd *)0)
702 printf("?Invalid help command %s\n", arg);
704 printf("%s\n", c->help);
709 settrace(int ign1, char *ign2[])
714 printf("Packet tracing %s.\n", trace ? "on" : "off");
718 setverbose(int ign1, char *ign2[])
723 printf("Verbose mode %s.\n", verbose ? "on" : "off");