Obsolete code removal
[people/sha0/gpxe.git] / contrib / 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 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.
16  */
17
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23
24 #ifndef lint
25 static char sccsid[] = "@(#)main.c      5.8 (Berkeley) 10/11/88";
26 #endif /* not lint */
27
28 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
29
30 /*
31  * TFTP User Program -- Command Interface.
32  */
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/file.h>
36
37 #include <netinet/in.h>
38
39 #include <signal.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <setjmp.h>
43 #include <ctype.h>
44 #include <netdb.h>
45
46 #define TIMEOUT         5               /* secs between rexmt's */
47
48 struct  sockaddr_in sin;
49 int     f;
50 short   port;
51 int     trace;
52 int     verbose;
53 int     connected;
54 char    mode[32];
55 char    line[200];
56 int     margc;
57 char    *margv[20];
58 char    *prompt = "tftp";
59 jmp_buf toplevel;
60 void    intr(int);
61 struct  servent *sp;
62
63 int     segsize = 512;
64
65 int     quit(), help(), setverbose(), settrace(), status();
66 int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
67 int     setbinary(), setascii(), setblocksize();
68
69 #define HELPINDENT (sizeof("connect"))
70
71 struct cmd {
72         char    *name;
73         char    *help;
74         int     (*handler)();
75 };
76
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";
91
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 },
107         0
108 };
109
110 struct  cmd *getcmd();
111 char    *tail();
112 char    *index();
113 char    *rindex();
114
115 main(argc, argv)
116         char *argv[];
117 {
118         struct sockaddr_in sin;
119         int top;
120
121         sp = getservbyname("tftp", "udp");
122         if (sp == 0) {
123                 fprintf(stderr, "tftp: udp/tftp: unknown service\n");
124                 exit(1);
125         }
126         f = socket(AF_INET, SOCK_DGRAM, 0);
127         if (f < 0) {
128                 perror("tftp: socket");
129                 exit(3);
130         }
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");
135                 exit(1);
136         }
137         strcpy(mode, "netascii");
138         signal(SIGINT, intr);
139         if (argc > 1) {
140                 if (setjmp(toplevel) != 0)
141                         exit(0);
142                 setpeer(argc, argv);
143         }
144         top = setjmp(toplevel) == 0;
145         for (;;)
146                 command(top);
147 }
148
149 char    hostname[100];
150
151 setpeer(argc, argv)
152         int argc;
153         char *argv[];
154 {
155         struct hostent *host;
156
157         if (argc < 2) {
158                 strcpy(line, "Connect ");
159                 printf("(to) ");
160                 fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
161                 makeargv();
162                 argc = margc;
163                 argv = margv;
164         }
165         if (argc > 3) {
166                 printf("usage: %s host-name [port]\n", argv[0]);
167                 return;
168         }
169         host = gethostbyname(argv[1]);
170         if (host) {
171                 sin.sin_family = host->h_addrtype;
172                 bcopy(host->h_addr, &sin.sin_addr, host->h_length);
173                 strcpy(hostname, host->h_name);
174         } else {
175                 sin.sin_family = AF_INET;
176                 sin.sin_addr.s_addr = inet_addr(argv[1]);
177                 if (sin.sin_addr.s_addr == -1) {
178                         connected = 0;
179                         printf("%s: unknown host\n", argv[1]);
180                         return;
181                 }
182                 strcpy(hostname, argv[1]);
183         }
184         port = sp->s_port;
185         if (argc == 3) {
186                 port = atoi(argv[2]);
187                 if (port < 0) {
188                         printf("%s: bad port number\n", argv[2]);
189                         connected = 0;
190                         return;
191                 }
192                 port = htons(port);
193         }
194         connected = 1;
195 }
196
197 struct  modes {
198         char *m_name;
199         char *m_mode;
200 } modes[] = {
201         { "ascii",      "netascii" },
202         { "netascii",   "netascii" },
203         { "binary",     "octet" },
204         { "image",      "octet" },
205         { "octet",     "octet" },
206 /*      { "mail",       "mail" },       */
207         { 0,            0 }
208 };
209
210 modecmd(argc, argv)
211         char *argv[];
212 {
213         register struct modes *p;
214         char *sep;
215
216         if (argc < 2) {
217                 printf("Using %s mode to transfer files.\n", mode);
218                 return;
219         }
220         if (argc == 2) {
221                 for (p = modes; p->m_name; p++)
222                         if (strcmp(argv[1], p->m_name) == 0)
223                                 break;
224                 if (p->m_name) {
225                         setmode(p->m_mode);
226                         return;
227                 }
228                 printf("%s: unknown mode\n", argv[1]);
229                 /* drop through and print usage message */
230         }
231
232         printf("usage: %s [", argv[0]);
233         sep = " ";
234         for (p = modes; p->m_name; p++) {
235                 printf("%s%s", sep, p->m_name);
236                 if (*sep == ' ')
237                         sep = " | ";
238         }
239         printf(" ]\n");
240         return;
241 }
242
243 setbinary(argc, argv)
244 char *argv[];
245 {       setmode("octet");
246 }
247
248 setascii(argc, argv)
249 char *argv[];
250 {       setmode("netascii");
251 }
252
253 setmode(newmode)
254 char *newmode;
255 {
256         strcpy(mode, newmode);
257         if (verbose)
258                 printf("mode set to %s\n", mode);
259 }
260
261
262 /*
263  * Send file(s).
264  */
265 put(argc, argv)
266         char *argv[];
267 {
268         int fd;
269         register int n;
270         register char *cp, *targ;
271
272         if (argc < 2) {
273                 strcpy(line, "send ");
274                 printf("(file) ");
275                 fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
276                 makeargv();
277                 argc = margc;
278                 argv = margv;
279         }
280         if (argc < 2) {
281                 putusage(argv[0]);
282                 return;
283         }
284         targ = argv[argc - 1];
285         if (index(argv[argc - 1], ':')) {
286                 char *cp;
287                 struct hostent *hp;
288
289                 for (n = 1; n < argc - 1; n++)
290                         if (index(argv[n], ':')) {
291                                 putusage(argv[0]);
292                                 return;
293                         }
294                 cp = argv[argc - 1];
295                 targ = index(cp, ':');
296                 *targ++ = 0;
297                 hp = gethostbyname(cp);
298                 if (hp == NULL) {
299                         fprintf(stderr, "tftp: %s: ", cp);
300                         herror((char *)NULL);
301                         return;
302                 }
303                 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
304                 sin.sin_family = hp->h_addrtype;
305                 connected = 1;
306                 strcpy(hostname, hp->h_name);
307         }
308         if (!connected) {
309                 printf("No target machine specified.\n");
310                 return;
311         }
312         if (argc < 4) {
313                 cp = argc == 2 ? tail(targ) : argv[1];
314                 fd = open(cp, O_RDONLY);
315                 if (fd < 0) {
316                         fprintf(stderr, "tftp: "); perror(cp);
317                         return;
318                 }
319                 if (verbose)
320                         printf("putting %s to %s:%s [%s]\n",
321                                 cp, hostname, targ, mode);
322                 sin.sin_port = port;
323                 sendfile(fd, targ, mode);
324                 return;
325         }
326                                 /* this assumes the target is a directory */
327                                 /* on a remote unix system.  hmmmm.  */
328         cp = index(targ, '\0'); 
329         *cp++ = '/';
330         for (n = 1; n < argc - 1; n++) {
331                 strcpy(cp, tail(argv[n]));
332                 fd = open(argv[n], O_RDONLY);
333                 if (fd < 0) {
334                         fprintf(stderr, "tftp: "); perror(argv[n]);
335                         continue;
336                 }
337                 if (verbose)
338                         printf("putting %s to %s:%s [%s]\n",
339                                 argv[n], hostname, targ, mode);
340                 sin.sin_port = port;
341                 sendfile(fd, targ, mode);
342         }
343 }
344
345 putusage(s)
346         char *s;
347 {
348         printf("usage: %s file ... host:target, or\n", s);
349         printf("       %s file ... target (when already connected)\n", s);
350 }
351
352 /*
353  * Receive file(s).
354  */
355 get(argc, argv)
356         char *argv[];
357 {
358         int fd;
359         register int n;
360         register char *cp;
361         char *src;
362
363         if (argc < 2) {
364                 strcpy(line, "get ");
365                 printf("(files) ");
366                 fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
367                 makeargv();
368                 argc = margc;
369                 argv = margv;
370         }
371         if (argc < 2) {
372                 getusage(argv[0]);
373                 return;
374         }
375         if (!connected) {
376                 for (n = 1; n < argc ; n++)
377                         if (index(argv[n], ':') == 0) {
378                                 getusage(argv[0]);
379                                 return;
380                         }
381         }
382         for (n = 1; n < argc ; n++) {
383                 src = index(argv[n], ':');
384                 if (src == NULL)
385                         src = argv[n];
386                 else {
387                         struct hostent *hp;
388
389                         *src++ = 0;
390                         hp = gethostbyname(argv[n]);
391                         if (hp == NULL) {
392                                 fprintf(stderr, "tftp: %s: ", argv[n]);
393                                 herror((char *)NULL);
394                                 continue;
395                         }
396                         bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
397                         sin.sin_family = hp->h_addrtype;
398                         connected = 1;
399                         strcpy(hostname, hp->h_name);
400                 }
401                 if (argc < 4) {
402                         cp = argc == 3 ? argv[2] : tail(src);
403                         fd = creat(cp, 0644);
404                         if (fd < 0) {
405                                 fprintf(stderr, "tftp: "); perror(cp);
406                                 return;
407                         }
408                         if (verbose)
409                                 printf("getting from %s:%s to %s [%s]\n",
410                                         hostname, src, cp, mode);
411                         sin.sin_port = port;
412                         recvfile(fd, src, mode);
413                         break;
414                 }
415                 cp = tail(src);         /* new .. jdg */
416                 fd = creat(cp, 0644);
417                 if (fd < 0) {
418                         fprintf(stderr, "tftp: "); perror(cp);
419                         continue;
420                 }
421                 if (verbose)
422                         printf("getting from %s:%s to %s [%s]\n",
423                                 hostname, src, cp, mode);
424                 sin.sin_port = port;
425                 recvfile(fd, src, mode);
426         }
427 }
428
429 getusage(s)
430 char * s;
431 {
432         printf("usage: %s host:file host:file ... file, or\n", s);
433         printf("       %s file file ... file if connected\n", s);
434 }
435
436 int     rexmtval = TIMEOUT;
437
438 setrexmt(argc, argv)
439         char *argv[];
440 {
441         int t;
442
443         if (argc < 2) {
444                 strcpy(line, "Rexmt-timeout ");
445                 printf("(value) ");
446                 fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
447                 makeargv();
448                 argc = margc;
449                 argv = margv;
450         }
451         if (argc != 2) {
452                 printf("usage: %s value\n", argv[0]);
453                 return;
454         }
455         t = atoi(argv[1]);
456         if (t < 0)
457                 printf("%d: bad value\n", t);
458         else
459                 rexmtval = t;
460 }
461
462 int     maxtimeout = 5 * TIMEOUT;
463
464 settimeout(argc, argv)
465         char *argv[];
466 {
467         int t;
468
469         if (argc < 2) {
470                 strcpy(line, "Maximum-timeout ");
471                 printf("(value) ");
472                 fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
473                 makeargv();
474                 argc = margc;
475                 argv = margv;
476         }
477         if (argc != 2) {
478                 printf("usage: %s value\n", argv[0]);
479                 return;
480         }
481         t = atoi(argv[1]);
482         if (t < 0)
483                 printf("%d: bad value\n", t);
484         else
485                 maxtimeout = t;
486 }
487
488 status(argc, argv)
489         char *argv[];
490 {
491         if (connected)
492                 printf("Connected to %s.\n", hostname);
493         else
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);
499 }
500
501 void intr(int sig)
502 {
503         signal(SIGALRM, SIG_IGN);
504         alarm(0);
505         longjmp(toplevel, -1);
506 }
507
508 char *
509 tail(filename)
510         char *filename;
511 {
512         register char *s;
513         
514         while (*filename) {
515                 s = rindex(filename, '/');
516                 if (s == NULL)
517                         break;
518                 if (s[1])
519                         return (s + 1);
520                 *s = '\0';
521         }
522         return (filename);
523 }
524
525 /*
526  * Command parser.
527  */
528 command(top)
529         int top;
530 {
531         register struct cmd *c;
532
533         if (!top)
534                 putchar('\n');
535         for (;;) {
536                 printf("%s> ", prompt);
537                 if (fgets(line, sizeof(line), stdin) == 0) {
538                         if (feof(stdin)) {
539                                 quit();
540                         } else {
541                                 continue;
542                         }
543                 }
544                 if (line[0] == 0)
545                         continue;
546                 makeargv();
547                 c = getcmd(margv[0]);
548                 if (c == (struct cmd *)-1) {
549                         printf("?Ambiguous command\n");
550                         continue;
551                 }
552                 if (c == 0) {
553                         printf("?Invalid command\n");
554                         continue;
555                 }
556                 (*c->handler)(margc, margv);
557         }
558 }
559
560 struct cmd *
561 getcmd(name)
562         register char *name;
563 {
564         register char *p, *q;
565         register struct cmd *c, *found;
566         register int nmatches, longest;
567
568         longest = 0;
569         nmatches = 0;
570         found = 0;
571         for (c = cmdtab; p = c->name; c++) {
572                 for (q = name; *q == *p++; q++)
573                         if (*q == 0)            /* exact match? */
574                                 return (c);
575                 if (!*q) {                      /* the name was a prefix */
576                         if (q - name > longest) {
577                                 longest = q - name;
578                                 nmatches = 1;
579                                 found = c;
580                         } else if (q - name == longest)
581                                 nmatches++;
582                 }
583         }
584         if (nmatches > 1)
585                 return ((struct cmd *)-1);
586         return (found);
587 }
588
589 /*
590  * Slice a string up into argc/argv.
591  */
592 makeargv()
593 {
594         register char *cp;
595         register char **argp = margv;
596
597         margc = 0;
598         for (cp = line; *cp;) {
599                 while (isspace(*cp))
600                         cp++;
601                 if (*cp == '\0')
602                         break;
603                 *argp++ = cp;
604                 margc += 1;
605                 while (*cp != '\0' && !isspace(*cp))
606                         cp++;
607                 if (*cp == '\0')
608                         break;
609                 *cp++ = '\0';
610         }
611         *argp++ = 0;
612 }
613
614 /*VARARGS*/
615 quit()
616 {
617         exit(0);
618 }
619
620 /*
621  * Help command.
622  */
623 help(argc, argv)
624         int argc;
625         char *argv[];
626 {
627         register struct cmd *c;
628
629         if (argc == 1) {
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);
633                 return;
634         }
635         while (--argc > 0) {
636                 register char *arg;
637                 arg = *++argv;
638                 c = getcmd(arg);
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);
643                 else
644                         printf("%s\n", c->help);
645         }
646 }
647
648 /*VARARGS*/
649 settrace()
650 {
651         trace = !trace;
652         printf("Packet tracing %s.\n", trace ? "on" : "off");
653 }
654
655 /*VARARGS*/
656 setverbose()
657 {
658         verbose = !verbose;
659         printf("Verbose mode %s.\n", verbose ? "on" : "off");
660 }
661
662 setblocksize(argc, argv)
663         char *argv[];
664 {
665         int t;
666
667         if (argc < 2) {
668                 strcpy(line, "blocksize ");
669                 printf("(value) ");
670                 fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
671                 makeargv();
672                 argc = margc;
673                 argv = margv;
674         }
675         if (argc != 2) {
676                 printf("usage: %s value\n", argv[0]);
677                 return;
678         }
679         t = atoi(argv[1]);
680         if (t < 8 || t > 1432)
681                 printf("%d: bad value\n", t);
682         else
683                 segsize = t;
684 }