OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / tftp / main.c
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
20  *
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
31  * SUCH DAMAGE.
32  */
33
34 char copyright[] =
35   "@(#) Copyright (c) 1983 Regents of the University of California.\n"
36   "All rights reserved.\n";
37
38 /*
39  * From: @(#)main.c     5.10 (Berkeley) 3/1/91
40  */
41 char main_rcsid[] = 
42   "$Id: main.c,v 1.9 1996/11/25 18:42:46 dholland Exp $";
43
44 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
45
46 /*
47  * TFTP User Program -- Command Interface.
48  */
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <sys/file.h>
52
53 #include <netinet/in.h>
54 #include <netinet/ip.h>
55 #include <arpa/inet.h>
56
57 #include <signal.h>
58 #include <stdio.h>
59 #include <errno.h>
60 #include <stdlib.h>
61 #include <setjmp.h>
62 #include <string.h>
63 #include <ctype.h>
64 #include <netdb.h>
65 #include <unistd.h>
66
67 #define TIMEOUT         5               /* secs between rexmt's */
68
69 struct sockaddr_in s_inn;
70 int f;
71 int trace;
72 int verbose;
73 int rexmtval = TIMEOUT;
74 int maxtimeout = 5 * TIMEOUT;
75 sigjmp_buf toplevel;
76 void sendfile(int fd, char *name, char *modestr);
77 void recvfile(int fd, char *name, char *modestr);
78
79
80 static int connected;
81 static short port;
82 static char mode[32];
83 static char line[200];
84 static int margc;
85 static char *margv[20];
86 static const char *prompt = "tftp";
87 static struct servent *sp;
88
89 static void intr(int);
90
91 void makeargv(void);
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);
109
110 #define HELPINDENT ((int) sizeof("connect"))
111
112 struct cmd {
113         const char *name;
114         const char *help;
115         void (*handler)(int, char *[]);
116 };
117
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";
131
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 },
146         { 0 }
147 };
148
149 static struct cmd *getcmd(const char *name);
150 static char *tail(char *filename);
151
152 int
153 main(int argc, char *argv[])
154 {
155         struct sockaddr_in s_in;
156         int top;
157
158         sp = getservbyname("tftp", "udp");
159         if (sp == 0) {
160                 fprintf(stderr, "tftp: udp/tftp: unknown service\n");
161                 exit(1);
162         }
163         f = socket(AF_INET, SOCK_DGRAM, 0);
164         if (f < 0) {
165                 perror("tftp: socket");
166                 exit(3);
167         }
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");
172                 exit(1);
173         }
174         strcpy(mode, "netascii");
175         signal(SIGINT, intr);
176         if (argc > 1) {
177                 if (sigsetjmp(toplevel, 1) != 0)
178                         exit(0);
179                 setpeer(argc, argv);
180         }
181         top = sigsetjmp(toplevel, 1) == 0;
182         for (;;)
183                 command(top);
184 }
185
186 static char hostname[100];
187
188 void
189 setpeer(int argc, char *argv[])
190 {
191         struct hostent *host;
192
193         if (argc < 2) {
194                 strcpy(line, "Connect ");
195                 printf("(to) ");
196                 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
197                 makeargv();
198                 argc = margc;
199                 argv = margv;
200         }
201         if (argc > 3) {
202                 printf("usage: %s host-name [port]\n", argv[0]);
203                 return;
204         }
205         host = gethostbyname(argv[1]);
206         if (host) {
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);
210                 }
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;
214         } 
215         else {
216                 s_inn.sin_family = AF_INET;
217                 if (!inet_aton(argv[1], &s_inn.sin_addr)) {
218                         connected = 0;
219                         printf("%s: unknown host\n", argv[1]);
220                         return;
221                 }
222                 strcpy(hostname, argv[1]);
223         }
224         port = sp->s_port;
225         if (argc == 3) {
226                 port = atoi(argv[2]);
227                 if (port < 0) {
228                         printf("%s: bad port number\n", argv[2]);
229                         connected = 0;
230                         return;
231                 }
232                 port = htons(port);
233         }
234         connected = 1;
235 }
236
237 struct  modes {
238         const char *m_name;
239         const char *m_mode;
240 } modes[] = {
241         { "ascii",      "netascii" },
242         { "netascii",   "netascii" },
243         { "binary",     "octet" },
244         { "image",      "octet" },
245         { "octet",      "octet" },
246 /*      { "mail",       "mail" },       */
247         { 0,            0 }
248 };
249
250 void
251 modecmd(int argc, char *argv[])
252 {
253         register struct modes *p;
254         const char *sep;
255
256         if (argc < 2) {
257                 printf("Using %s mode to transfer files.\n", mode);
258                 return;
259         }
260         if (argc == 2) {
261                 for (p = modes; p->m_name; p++)
262                         if (strcmp(argv[1], p->m_name) == 0)
263                                 break;
264                 if (p->m_name) {
265                         setmode(p->m_mode);
266                         return;
267                 }
268                 printf("%s: unknown mode\n", argv[1]);
269                 /* drop through and print usage message */
270         }
271
272         printf("usage: %s [", argv[0]);
273         sep = " ";
274         for (p = modes; p->m_name; p++) {
275                 printf("%s%s", sep, p->m_name);
276                 if (*sep == ' ')
277                         sep = " | ";
278         }
279         printf(" ]\n");
280         return;
281 }
282
283 void
284 setbinary(int argc, char *argv[])
285 {
286         (void)argc;
287         (void)argv;
288         setmode("octet");
289 }
290
291 void
292 setascii(int argc, char *argv[])
293 {
294         (void)argc;
295         (void)argv;
296         setmode("netascii");
297 }
298
299 void
300 setmode(const char *newmode)
301 {
302         strcpy(mode, newmode);
303         if (verbose)
304                 printf("mode set to %s\n", mode);
305 }
306
307
308 /*
309  * Send file(s).
310  */
311 void
312 put(int argc, char *argv[])
313 {
314         int fd;
315         register int n;
316         register char *ccp, *targ;
317
318         if (argc < 2) {
319                 strcpy(line, "send ");
320                 printf("(file) ");
321                 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
322                 makeargv();
323                 argc = margc;
324                 argv = margv;
325         }
326         if (argc < 2) {
327                 putusage(argv[0]);
328                 return;
329         }
330         targ = argv[argc - 1];
331         if (index(argv[argc - 1], ':')) {
332                 char *cp;
333                 struct hostent *hp;
334
335                 for (n = 1; n < argc - 1; n++)
336                         if (index(argv[n], ':')) {
337                                 putusage(argv[0]);
338                                 return;
339                         }
340                 cp = argv[argc - 1];
341                 targ = index(cp, ':');
342                 *targ++ = 0;
343                 hp = gethostbyname(cp);
344                 if (hp == NULL) {
345                         fprintf(stderr, "tftp: %s: ", cp);
346                         herror((char *)NULL);
347                         return;
348                 }
349                 if (hp->h_length > (int)sizeof(s_inn.sin_addr)) {
350                         hp->h_length = sizeof(s_inn.sin_addr);
351                 }
352                 memcpy(&s_inn.sin_addr, hp->h_addr, hp->h_length);
353                 s_inn.sin_family = hp->h_addrtype;
354                 connected = 1;
355                 strncpy(hostname, hp->h_name, sizeof(hostname));
356                 hostname[sizeof(hostname)-1] = 0;
357         }
358         if (!connected) {
359                 printf("No target machine specified.\n");
360                 return;
361         }
362         if (argc < 4) {
363                 ccp = argc == 2 ? tail(targ) : argv[1];
364                 fd = open(ccp, O_RDONLY);
365                 if (fd < 0) {
366                         fprintf(stderr, "tftp: "); 
367                         perror(ccp);
368                         return;
369                 }
370                 if (verbose)
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);
375                 return;
376         }
377                                 /* this assumes the target is a directory */
378                                 /* on a remote unix system.  hmmmm.  */
379         ccp = targ+strlen(targ);
380         *ccp++ = '/';
381         for (n = 1; n < argc - 1; n++) {
382                 strcpy(ccp, tail(argv[n]));
383                 fd = open(argv[n], O_RDONLY);
384                 if (fd < 0) {
385                         fprintf(stderr, "tftp: "); perror(argv[n]);
386                         continue;
387                 }
388                 if (verbose)
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);
393         }
394 }
395
396 void
397 putusage(const char *s)
398 {
399         printf("usage: %s file ... host:target, or\n", s);
400         printf("       %s file ... target (when already connected)\n", s);
401 }
402
403 /*
404  * Receive file(s).
405  */
406 void
407 get(int argc, char *argv[])
408 {
409         int fd;
410         register int n;
411         register char *cp;
412         char *src;
413
414         if (argc < 2) {
415                 strcpy(line, "get ");
416                 printf("(files) ");
417                 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
418                 makeargv();
419                 argc = margc;
420                 argv = margv;
421         }
422         if (argc < 2) {
423                 getusage(argv[0]);
424                 return;
425         }
426         if (!connected) {
427                 for (n = 1; n < argc ; n++)
428                         if (index(argv[n], ':') == 0) {
429                                 getusage(argv[0]);
430                                 return;
431                         }
432         }
433         for (n = 1; n < argc ; n++) {
434                 src = index(argv[n], ':');
435                 if (src == NULL)
436                         src = argv[n];
437                 else {
438                         struct hostent *hp;
439
440                         *src++ = 0;
441                         hp = gethostbyname(argv[n]);
442                         if (hp == NULL) {
443                                 fprintf(stderr, "tftp: %s: ", argv[n]);
444                                 herror(NULL);
445                                 continue;
446                         }
447                         if (hp->h_length > (int)sizeof(s_inn.sin_addr)) {
448                                 hp->h_length = sizeof(s_inn.sin_addr);
449                         }
450                         memcpy(&s_inn.sin_addr, hp->h_addr, hp->h_length);
451                         s_inn.sin_family = hp->h_addrtype;
452                         connected = 1;
453                         strncpy(hostname, hp->h_name, sizeof(hostname));
454                         hostname[sizeof(hostname)-1] = 0;
455                 }
456                 if (argc < 4) {
457                         cp = argc == 3 ? argv[2] : tail(src);
458                         fd = creat(cp, 0644);
459                         if (fd < 0) {
460                                 fprintf(stderr, "tftp: "); perror(cp);
461                                 return;
462                         }
463                         if (verbose)
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);
468                         break;
469                 }
470                 cp = tail(src);         /* new .. jdg */
471                 fd = creat(cp, 0644);
472                 if (fd < 0) {
473                         fprintf(stderr, "tftp: "); perror(cp);
474                         continue;
475                 }
476                 if (verbose)
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);
481         }
482 }
483
484 void
485 getusage(const char *s)
486 {
487         printf("usage: %s host:file host:file ... file, or\n", s);
488         printf("       %s file file ... file if connected\n", s);
489 }
490
491
492 void
493 setrexmt(int argc, char *argv[])
494 {
495         int t;
496
497         if (argc < 2) {
498                 strcpy(line, "Rexmt-timeout ");
499                 printf("(value) ");
500                 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
501                 makeargv();
502                 argc = margc;
503                 argv = margv;
504         }
505         if (argc != 2) {
506                 printf("usage: %s value\n", argv[0]);
507                 return;
508         }
509         t = atoi(argv[1]);
510         if (t < 0)
511                 printf("%s: bad value\n", argv[1]);
512         else
513                 rexmtval = t;
514 }
515
516 void
517 settimeout(int argc, char *argv[])
518 {
519         int t;
520
521         if (argc < 2) {
522                 strcpy(line, "Maximum-timeout ");
523                 printf("(value) ");
524                 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
525                 makeargv();
526                 argc = margc;
527                 argv = margv;
528         }
529         if (argc != 2) {
530                 printf("usage: %s value\n", argv[0]);
531                 return;
532         }
533         t = atoi(argv[1]);
534         if (t < 0)
535                 printf("%s: bad value\n", argv[1]);
536         else
537                 maxtimeout = t;
538 }
539
540 void
541 status(int argc, char *argv[])
542 {
543         (void)argc;
544         (void)argv;
545
546         if (connected)
547                 printf("Connected to %s.\n", hostname);
548         else
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);
554 }
555
556 static
557 void
558 intr(int ignore)
559 {
560         (void)ignore;
561
562         signal(SIGALRM, SIG_IGN);
563         alarm(0);
564         siglongjmp(toplevel, -1);
565 }
566
567 static
568 char *
569 tail(char *filename)
570 {
571         register char *s;
572         
573         while (*filename) {
574                 s = strrchr(filename, '/');
575                 if (s == NULL)
576                         break;
577                 if (s[1])
578                         return (s + 1);
579                 *s = '\0';
580         }
581         return filename;
582 }
583
584 /*
585  * Command parser.
586  */
587 void
588 command(int top)
589 {
590         register struct cmd *c;
591
592         if (!top)
593                 putchar('\n');
594         for (;;) {
595                 printf("%s> ", prompt);
596                 if (fgets(line, sizeof(line), stdin) == 0) {
597                         if (feof(stdin)) {
598                                 quit(0, NULL);
599                         } else {
600                                 continue;
601                         }
602                 }
603                 if (line[0] == 0)
604                         continue;
605                 makeargv();
606                 c = getcmd(margv[0]);
607                 if (c == (struct cmd *)-1) {
608                         printf("?Ambiguous command\n");
609                         continue;
610                 }
611                 if (c == 0) {
612                         printf("?Invalid command\n");
613                         continue;
614                 }
615                 (*c->handler)(margc, margv);
616         }
617 }
618
619 struct cmd *
620 getcmd(const char *name)
621 {
622         const char *p, *q;
623         struct cmd *c, *found;
624         int nmatches, longest;
625
626         longest = 0;
627         nmatches = 0;
628         found = 0;
629         for (c = cmdtab; (p = c->name)!=NULL; c++) {
630                 for (q = name; *q == *p++; q++)
631                         if (*q == 0)            /* exact match? */
632                                 return (c);
633                 if (!*q) {                      /* the name was a prefix */
634                         if (q - name > longest) {
635                                 longest = q - name;
636                                 nmatches = 1;
637                                 found = c;
638                         } else if (q - name == longest)
639                                 nmatches++;
640                 }
641         }
642         if (nmatches > 1)
643                 return ((struct cmd *)-1);
644         return (found);
645 }
646
647 /*
648  * Slice a string up into argc/argv.
649  */
650 void
651 makeargv(void)
652 {
653         register char *cp;
654         register char **argp = margv;
655
656         margc = 0;
657         for (cp = line; *cp;) {
658                 while (isspace(*cp))
659                         cp++;
660                 if (*cp == '\0')
661                         break;
662                 *argp++ = cp;
663                 margc += 1;
664                 while (*cp != '\0' && !isspace(*cp))
665                         cp++;
666                 if (*cp == '\0')
667                         break;
668                 *cp++ = '\0';
669         }
670         *argp++ = 0;
671 }
672
673 void
674 quit(int ign1, char *ign2[])
675 {
676         (void)ign1;
677         (void)ign2;
678         exit(0);
679 }
680
681 /*
682  * Help command.
683  */
684 void
685 help(int argc, char *argv[])
686 {
687         register struct cmd *c;
688
689         if (argc == 1) {
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);
693                 return;
694         }
695         while (--argc > 0) {
696                 register char *arg;
697                 arg = *++argv;
698                 c = getcmd(arg);
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);
703                 else
704                         printf("%s\n", c->help);
705         }
706 }
707
708 void
709 settrace(int ign1, char *ign2[])
710 {
711         (void)ign1;
712         (void)ign2;
713         trace = !trace;
714         printf("Packet tracing %s.\n", trace ? "on" : "off");
715 }
716
717 void
718 setverbose(int ign1, char *ign2[])
719 {
720         (void)ign1;
721         (void)ign2;
722         verbose = !verbose;
723         printf("Verbose mode %s.\n", verbose ? "on" : "off");
724 }