]> git.saurik.com Git - apple/network_cmds.git/blame - tftp.tproj/main.c
network_cmds-176.tar.gz
[apple/network_cmds.git] / tftp.tproj / main.c
CommitLineData
b7080c8e
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ac2f15b3
A
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
b7080c8e
A
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ac2f15b3
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
b7080c8e
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright (c) 1983, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58
59#ifndef lint
60static char copyright[] =
61"@(#) Copyright (c) 1983, 1993\n\
62 The Regents of the University of California. All rights reserved.\n";
63#endif /* not lint */
64
65/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
66
67/*
68 * TFTP User Program -- Command Interface.
69 */
70#include <sys/types.h>
71#include <sys/socket.h>
72#include <sys/file.h>
73
74#include <netinet/in.h>
75
76#include <arpa/inet.h>
77
78#include <ctype.h>
79#include <errno.h>
80#include <netdb.h>
81#include <setjmp.h>
82#include <signal.h>
83#include <stdio.h>
84#include <stdlib.h>
85#include <string.h>
86#include <unistd.h>
87
88#include "extern.h"
89
90#define TIMEOUT 5 /* secs between rexmt's */
91
92struct sockaddr_in peeraddr;
93int f;
94short port;
95int trace;
96int verbose;
97int connected;
98char mode[32];
99char line[BUFSIZ];
100int margc;
101char *margv[20];
102char *prompt = "tftp";
103jmp_buf toplevel;
104void intr();
105struct servent *sp;
106
107void get __P((int, char **));
108void help __P((int, char **));
109void modecmd __P((int, char **));
110void put __P((int, char **));
111void quit __P((int, char **));
112void setascii __P((int, char **));
113void setbinary __P((int, char **));
114void setpeer __P((int, char **));
115void setrexmt __P((int, char **));
116void settimeout __P((int, char **));
117void settrace __P((int, char **));
118void setverbose __P((int, char **));
119void status __P((int, char **));
120
121static __dead void command __P((void));
122
123static void getusage __P((char *));
124static void makeargv __P((void));
125static void putusage __P((char *));
126static void settftpmode __P((char *));
127
128#define HELPINDENT (sizeof("connect"))
129
130struct cmd {
131 char *name;
132 char *help;
133 void (*handler) __P((int, char **));
134};
135
136char vhelp[] = "toggle verbose mode";
137char thelp[] = "toggle packet tracing";
138char chelp[] = "connect to remote tftp";
139char qhelp[] = "exit tftp";
140char hhelp[] = "print help information";
141char shelp[] = "send file";
142char rhelp[] = "receive file";
143char mhelp[] = "set file transfer mode";
144char sthelp[] = "show current status";
145char xhelp[] = "set per-packet retransmission timeout";
146char ihelp[] = "set total retransmission timeout";
147char ashelp[] = "set mode to netascii";
148char bnhelp[] = "set mode to octet";
149
150struct cmd cmdtab[] = {
151 { "connect", chelp, setpeer },
152 { "mode", mhelp, modecmd },
153 { "put", shelp, put },
154 { "get", rhelp, get },
155 { "quit", qhelp, quit },
156 { "verbose", vhelp, setverbose },
157 { "trace", thelp, settrace },
158 { "status", sthelp, status },
159 { "binary", bnhelp, setbinary },
160 { "ascii", ashelp, setascii },
161 { "rexmt", xhelp, setrexmt },
162 { "timeout", ihelp, settimeout },
163 { "?", hhelp, help },
164 { 0 }
165};
166
167struct cmd *getcmd();
168char *tail();
169char *index();
170char *rindex();
171
172int
173main(argc, argv)
174 int argc;
175 char *argv[];
176{
177 struct sockaddr_in sin;
178
179 sp = getservbyname("tftp", "udp");
180 if (sp == 0) {
181 fprintf(stderr, "tftp: udp/tftp: unknown service\n");
182 exit(1);
183 }
184 f = socket(AF_INET, SOCK_DGRAM, 0);
185 if (f < 0) {
186 perror("tftp: socket");
187 exit(3);
188 }
189 bzero((char *)&sin, sizeof(sin));
190 sin.sin_family = AF_INET;
191 if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
192 perror("tftp: bind");
193 exit(1);
194 }
195 strcpy(mode, "netascii");
196 signal(SIGINT, intr);
197 if (argc > 1) {
198 if (setjmp(toplevel) != 0)
199 exit(0);
200 setpeer(argc, argv);
201 }
202 if (setjmp(toplevel) != 0)
203 (void)putchar('\n');
204 command();
205}
206
207char hostname[100];
208
209void
210setpeer(argc, argv)
211 int argc;
212 char *argv[];
213{
214 struct hostent *host;
215
216 if (argc < 2) {
217 strcpy(line, "Connect ");
218 printf("(to) ");
219 fgets(&line[strlen(line)], BUFSIZ-strlen(line)-1, stdin);
220 makeargv();
221 argc = margc;
222 argv = margv;
223 }
224 if (argc > 3) {
225 printf("usage: %s host-name [port]\n", argv[0]);
226 return;
227 }
228 host = gethostbyname(argv[1]);
229 if (host) {
230 peeraddr.sin_family = host->h_addrtype;
231 bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
232 strcpy(hostname, host->h_name);
233 } else {
234 peeraddr.sin_family = AF_INET;
235 peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
236 if (peeraddr.sin_addr.s_addr == -1) {
237 connected = 0;
238 printf("%s: unknown host\n", argv[1]);
239 return;
240 }
241 strcpy(hostname, argv[1]);
242 }
243 port = sp->s_port;
244 if (argc == 3) {
245 port = atoi(argv[2]);
246 if (port < 0) {
247 printf("%s: bad port number\n", argv[2]);
248 connected = 0;
249 return;
250 }
251 port = htons(port);
252 }
253 connected = 1;
254}
255
256struct modes {
257 char *m_name;
258 char *m_mode;
259} modes[] = {
260 { "ascii", "netascii" },
261 { "netascii", "netascii" },
262 { "binary", "octet" },
263 { "image", "octet" },
264 { "octet", "octet" },
265/* { "mail", "mail" }, */
266 { 0, 0 }
267};
268
269void
270modecmd(argc, argv)
271 int argc;
272 char *argv[];
273{
274 register struct modes *p;
275 char *sep;
276
277 if (argc < 2) {
278 printf("Using %s mode to transfer files.\n", mode);
279 return;
280 }
281 if (argc == 2) {
282 for (p = modes; p->m_name; p++)
283 if (strcmp(argv[1], p->m_name) == 0)
284 break;
285 if (p->m_name) {
286 settftpmode(p->m_mode);
287 return;
288 }
289 printf("%s: unknown mode\n", argv[1]);
290 /* drop through and print usage message */
291 }
292
293 printf("usage: %s [", argv[0]);
294 sep = " ";
295 for (p = modes; p->m_name; p++) {
296 printf("%s%s", sep, p->m_name);
297 if (*sep == ' ')
298 sep = " | ";
299 }
300 printf(" ]\n");
301 return;
302}
303
304void
305setbinary(argc, argv)
306 int argc;
307 char *argv[];
308{
309
310 settftpmode("octet");
311}
312
313void
314setascii(argc, argv)
315 int argc;
316 char *argv[];
317{
318
319 settftpmode("netascii");
320}
321
322static void
323settftpmode(newmode)
324 char *newmode;
325{
326 strcpy(mode, newmode);
327 if (verbose)
328 printf("mode set to %s\n", mode);
329}
330
331
332/*
333 * Send file(s).
334 */
335void
336put(argc, argv)
337 int argc;
338 char *argv[];
339{
340 int fd;
341 register int n;
342 register char *cp, *targ;
343
344 if (argc < 2) {
345 strcpy(line, "send ");
346 printf("(file) ");
347 fgets(&line[strlen(line)], BUFSIZ-strlen(line)-1, stdin);
348 makeargv();
349 argc = margc;
350 argv = margv;
351 }
352 if (argc < 2) {
353 putusage(argv[0]);
354 return;
355 }
356 targ = argv[argc - 1];
357 if (index(argv[argc - 1], ':')) {
358 char *cp;
359 struct hostent *hp;
360
361 for (n = 1; n < argc - 1; n++)
362 if (index(argv[n], ':')) {
363 putusage(argv[0]);
364 return;
365 }
366 cp = argv[argc - 1];
367 targ = index(cp, ':');
368 *targ++ = 0;
369 hp = gethostbyname(cp);
370 if (hp == NULL) {
371 fprintf(stderr, "tftp: %s: ", cp);
372 herror((char *)NULL);
373 return;
374 }
375 bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
376 peeraddr.sin_family = hp->h_addrtype;
377 connected = 1;
378 strcpy(hostname, hp->h_name);
379 }
380 if (!connected) {
381 printf("No target machine specified.\n");
382 return;
383 }
384 if (argc < 4) {
385 cp = argc == 2 ? tail(targ) : argv[1];
386 fd = open(cp, O_RDONLY);
387 if (fd < 0) {
388 fprintf(stderr, "tftp: "); perror(cp);
389 return;
390 }
391 if (verbose)
392 printf("putting %s to %s:%s [%s]\n",
393 cp, hostname, targ, mode);
394 peeraddr.sin_port = port;
395 tftp_sendfile(fd, targ, mode);
396 return;
397 }
398 /* this assumes the target is a directory */
399 /* on a remote unix system. hmmmm. */
400 cp = index(targ, '\0');
401 *cp++ = '/';
402 for (n = 1; n < argc - 1; n++) {
403 strcpy(cp, tail(argv[n]));
404 fd = open(argv[n], O_RDONLY);
405 if (fd < 0) {
406 fprintf(stderr, "tftp: "); perror(argv[n]);
407 continue;
408 }
409 if (verbose)
410 printf("putting %s to %s:%s [%s]\n",
411 argv[n], hostname, targ, mode);
412 peeraddr.sin_port = port;
413 tftp_sendfile(fd, targ, mode);
414 }
415}
416
417static void
418putusage(s)
419 char *s;
420{
421 printf("usage: %s file ... host:target, or\n", s);
422 printf(" %s file ... target (when already connected)\n", s);
423}
424
425/*
426 * Receive file(s).
427 */
428void
429get(argc, argv)
430 int argc;
431 char *argv[];
432{
433 int fd;
434 register int n;
435 register char *cp;
436 char *src;
437
438 if (argc < 2) {
439 strcpy(line, "get ");
440 printf("(files) ");
441 fgets(&line[strlen(line)], BUFSIZ-strlen(line)-1, stdin);
442 makeargv();
443 argc = margc;
444 argv = margv;
445 }
446 if (argc < 2) {
447 getusage(argv[0]);
448 return;
449 }
450 if (!connected) {
451 for (n = 1; n < argc ; n++)
452 if (index(argv[n], ':') == 0) {
453 getusage(argv[0]);
454 return;
455 }
456 }
457 for (n = 1; n < argc ; n++) {
458 src = index(argv[n], ':');
459 if (src == NULL)
460 src = argv[n];
461 else {
462 struct hostent *hp;
463
464 *src++ = 0;
465 hp = gethostbyname(argv[n]);
466 if (hp == NULL) {
467 fprintf(stderr, "tftp: %s: ", argv[n]);
468 herror((char *)NULL);
469 continue;
470 }
471 bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
472 hp->h_length);
473 peeraddr.sin_family = hp->h_addrtype;
474 connected = 1;
475 strcpy(hostname, hp->h_name);
476 }
477 if (argc < 4) {
478 cp = argc == 3 ? argv[2] : tail(src);
479 fd = creat(cp, 0644);
480 if (fd < 0) {
481 fprintf(stderr, "tftp: "); perror(cp);
482 return;
483 }
484 if (verbose)
485 printf("getting from %s:%s to %s [%s]\n",
486 hostname, src, cp, mode);
487 peeraddr.sin_port = port;
488 recvfile(fd, src, mode);
489 break;
490 }
491 cp = tail(src); /* new .. jdg */
492 fd = creat(cp, 0644);
493 if (fd < 0) {
494 fprintf(stderr, "tftp: "); perror(cp);
495 continue;
496 }
497 if (verbose)
498 printf("getting from %s:%s to %s [%s]\n",
499 hostname, src, cp, mode);
500 peeraddr.sin_port = port;
501 recvfile(fd, src, mode);
502 }
503}
504
505static void
506getusage(s)
507 char *s;
508{
509 printf("usage: %s host:file host:file ... file, or\n", s);
510 printf(" %s file file ... file if connected\n", s);
511}
512
513int rexmtval = TIMEOUT;
514
515void
516setrexmt(argc, argv)
517 int argc;
518 char *argv[];
519{
520 int t;
521
522 if (argc < 2) {
523 strcpy(line, "Rexmt-timeout ");
524 printf("(value) ");
525 fgets(&line[strlen(line)], BUFSIZ-strlen(line)-1, stdin);
526 makeargv();
527 argc = margc;
528 argv = margv;
529 }
530 if (argc != 2) {
531 printf("usage: %s value\n", argv[0]);
532 return;
533 }
534 t = atoi(argv[1]);
535 if (t < 0)
536 printf("%s: bad value\n", argv[1]);
537 else
538 rexmtval = t;
539}
540
541int maxtimeout = 5 * TIMEOUT;
542
543void
544settimeout(argc, argv)
545 int argc;
546 char *argv[];
547{
548 int t;
549
550 if (argc < 2) {
551 strcpy(line, "Maximum-timeout ");
552 printf("(value) ");
553 fgets(&line[strlen(line)], BUFSIZ-strlen(line)-1, stdin);
554 makeargv();
555 argc = margc;
556 argv = margv;
557 }
558 if (argc != 2) {
559 printf("usage: %s value\n", argv[0]);
560 return;
561 }
562 t = atoi(argv[1]);
563 if (t < 0)
564 printf("%s: bad value\n", argv[1]);
565 else
566 maxtimeout = t;
567}
568
569void
570status(argc, argv)
571 int argc;
572 char *argv[];
573{
574 if (connected)
575 printf("Connected to %s.\n", hostname);
576 else
577 printf("Not connected.\n");
578 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
579 verbose ? "on" : "off", trace ? "on" : "off");
580 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
581 rexmtval, maxtimeout);
582}
583
584void
585intr()
586{
587
588 signal(SIGALRM, SIG_IGN);
589 alarm(0);
590 longjmp(toplevel, -1);
591}
592
593char *
594tail(filename)
595 char *filename;
596{
597 register char *s;
598
599 while (*filename) {
600 s = rindex(filename, '/');
601 if (s == NULL)
602 break;
603 if (s[1])
604 return (s + 1);
605 *s = '\0';
606 }
607 return (filename);
608}
609
610/*
611 * Command parser.
612 */
613static __dead void
614command()
615{
616 register struct cmd *c;
617
618 for (;;) {
619 printf("%s> ", prompt);
620 if (fgets(line, BUFSIZ-1, stdin) == 0) {
621 if (feof(stdin)) {
622 exit(0);
623 } else {
624 continue;
625 }
626 }
627 if (line[0] == 0)
628 continue;
629 makeargv();
630 if (margc == 0)
631 continue;
632 c = getcmd(margv[0]);
633 if (c == (struct cmd *)-1) {
634 printf("?Ambiguous command\n");
635 continue;
636 }
637 if (c == 0) {
638 printf("?Invalid command\n");
639 continue;
640 }
641 (*c->handler)(margc, margv);
642 }
643}
644
645struct cmd *
646getcmd(name)
647 register char *name;
648{
649 register char *p, *q;
650 register struct cmd *c, *found;
651 register int nmatches, longest;
652
653 longest = 0;
654 nmatches = 0;
655 found = 0;
656 for (c = cmdtab; (p = c->name) != NULL; c++) {
657 for (q = name; *q == *p++; q++)
658 if (*q == 0) /* exact match? */
659 return (c);
660 if (!*q) { /* the name was a prefix */
661 if (q - name > longest) {
662 longest = q - name;
663 nmatches = 1;
664 found = c;
665 } else if (q - name == longest)
666 nmatches++;
667 }
668 }
669 if (nmatches > 1)
670 return ((struct cmd *)-1);
671 return (found);
672}
673
674/*
675 * Slice a string up into argc/argv.
676 */
677static void
678makeargv()
679{
680 register char *cp;
681 register char **argp = margv;
682
683 margc = 0;
684 for (cp = line; *cp;) {
685 while (isspace(*cp))
686 cp++;
687 if (*cp == '\0')
688 break;
689 *argp++ = cp;
690 margc += 1;
691 while (*cp != '\0' && !isspace(*cp))
692 cp++;
693 if (*cp == '\0')
694 break;
695 *cp++ = '\0';
696 }
697 *argp++ = 0;
698}
699
700void
701quit(argc, argv)
702 int argc;
703 char *argv[];
704{
705
706 exit(0);
707}
708
709/*
710 * Help command.
711 */
712void
713help(argc, argv)
714 int argc;
715 char *argv[];
716{
717 register struct cmd *c;
718
719 if (argc == 1) {
720 printf("Commands may be abbreviated. Commands are:\n\n");
721 for (c = cmdtab; c->name; c++)
722 printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
723 return;
724 }
725 while (--argc > 0) {
726 register char *arg;
727 arg = *++argv;
728 c = getcmd(arg);
729 if (c == (struct cmd *)-1)
730 printf("?Ambiguous help command %s\n", arg);
731 else if (c == (struct cmd *)0)
732 printf("?Invalid help command %s\n", arg);
733 else
734 printf("%s\n", c->help);
735 }
736}
737
738void
739settrace(argc, argv)
740 int argc;
741 char **argv;
742{
743 trace = !trace;
744 printf("Packet tracing %s.\n", trace ? "on" : "off");
745}
746
747void
748setverbose(argc, argv)
749 int argc;
750 char **argv;
751{
752 verbose = !verbose;
753 printf("Verbose mode %s.\n", verbose ? "on" : "off");
754}