standardize sccs keyword lines
[unix-history] / usr / src / usr.bin / tftp / main.c
CommitLineData
524aa063
SL
1#ifndef lint
2static char sccsid[] = "@(#)main.c 4.7 (Berkeley) %G%";
3#endif
c3353d83
SL
4
5/*
6 * TFTP User Program -- Command Interface.
7 */
8#include <sys/types.h>
c3353d83 9#include <sys/socket.h>
61ad9979 10#include <sys/file.h>
de3b21e8
SL
11
12#include <netinet/in.h>
13
c3353d83
SL
14#include <signal.h>
15#include <stdio.h>
16#include <errno.h>
17#include <setjmp.h>
18#include <ctype.h>
4d5e33bd 19#include <netdb.h>
c3353d83 20
61ad9979
SL
21#define TIMEOUT 5 /* secs between rexmt's */
22
de3b21e8 23struct sockaddr_in sin;
c3353d83 24int f;
c3353d83
SL
25int trace;
26int verbose;
27int connected;
28char mode[32];
29char line[200];
30int margc;
31char *margv[20];
32char *prompt = "tftp";
33jmp_buf toplevel;
34int intr();
4d5e33bd 35struct servent *sp;
c3353d83
SL
36
37int quit(), help(), setverbose(), settrace(), status();
61ad9979 38int get(), put(), setpeer(), setmode(), setrexmt(), settimeout();
c3353d83
SL
39
40#define HELPINDENT (sizeof("connect"))
41
42struct cmd {
43 char *name;
44 char *help;
45 int (*handler)();
46};
47
48char vhelp[] = "toggle verbose mode";
49char thelp[] = "toggle packet tracing";
50char chelp[] = "connect to remote tftp";
51char qhelp[] = "exit tftp";
52char hhelp[] = "print help information";
53char shelp[] = "send file";
54char rhelp[] = "receive file";
55char mhelp[] = "set file transfer mode";
56char sthelp[] = "show current status";
61ad9979
SL
57char xhelp[] = "set per-packet retransmission timeout";
58char ihelp[] = "set total retransmission timeout";
c3353d83
SL
59
60struct cmd cmdtab[] = {
61 { "connect", chelp, setpeer },
62 { "mode", mhelp, setmode },
63 { "put", shelp, put },
64 { "get", rhelp, get },
65 { "quit", qhelp, quit },
66 { "verbose", vhelp, setverbose },
67 { "trace", thelp, settrace },
68 { "status", sthelp, status },
61ad9979
SL
69 { "rexmt", xhelp, setrexmt },
70 { "timeout", ihelp, settimeout },
c3353d83
SL
71 { "?", hhelp, help },
72 0
73};
74
75struct cmd *getcmd();
76char *tail();
77char *index();
78char *rindex();
79
80main(argc, argv)
81 char *argv[];
82{
61ad9979
SL
83 struct sockaddr_in sin;
84 int top;
85
4d5e33bd
SL
86 sp = getservbyname("tftp", "udp");
87 if (sp == 0) {
88 fprintf(stderr, "tftp: udp/tftp: unknown service\n");
89 exit(1);
90 }
85b11450 91 f = socket(AF_INET, SOCK_DGRAM, 0, 0);
c3353d83 92 if (f < 0) {
61ad9979 93 perror("tftp: socket");
c3353d83
SL
94 exit(3);
95 }
61ad9979
SL
96 bzero((char *)&sin, sizeof (sin));
97 sin.sin_family = AF_INET;
98 if (bind(f, &sin, sizeof (sin)) < 0) {
99 perror("tftp: bind");
100 exit(1);
101 }
c3353d83 102 strcpy(mode, "netascii");
61ad9979 103 signal(SIGINT, intr);
c3353d83
SL
104 if (argc > 1) {
105 if (setjmp(toplevel) != 0)
106 exit(0);
107 setpeer(argc, argv);
108 }
61ad9979 109 top = setjmp(toplevel) == 0;
c3353d83 110 for (;;)
61ad9979 111 command(top);
c3353d83
SL
112}
113
4d5e33bd
SL
114char *hostname;
115char hnamebuf[32];
c3353d83
SL
116
117setpeer(argc, argv)
118 int argc;
119 char *argv[];
120{
121 register int c;
4d5e33bd 122 struct hostent *host;
c3353d83
SL
123
124 if (argc < 2) {
125 strcpy(line, "Connect ");
126 printf("(to) ");
127 gets(&line[strlen(line)]);
128 makeargv();
129 argc = margc;
130 argv = margv;
131 }
132 if (argc > 3) {
133 printf("usage: %s host-name [port]\n", argv[0]);
134 return;
135 }
4d5e33bd
SL
136 host = gethostbyname(argv[1]);
137 if (host) {
de3b21e8 138 sin.sin_family = host->h_addrtype;
4d5e33bd
SL
139 bcopy(host->h_addr, &sin.sin_addr, host->h_length);
140 hostname = host->h_name;
141 } else {
de3b21e8 142 sin.sin_family = AF_INET;
4d5e33bd
SL
143 sin.sin_addr.s_addr = inet_addr(argv[1]);
144 if (sin.sin_addr.s_addr == -1) {
145 connected = 0;
146 printf("%s: unknown host\n", argv[1]);
147 return;
148 }
149 strcpy(hnamebuf, argv[1]);
150 hostname = hnamebuf;
c3353d83 151 }
4d5e33bd 152 sin.sin_port = sp->s_port;
c3353d83
SL
153 if (argc == 3) {
154 sin.sin_port = atoi(argv[2]);
155 if (sin.sin_port < 0) {
156 printf("%s: bad port number\n", argv[2]);
157 connected = 0;
158 return;
159 }
26d9d18d 160 sin.sin_port = htons((u_short)sin.sin_port);
4d5e33bd 161 }
c3353d83
SL
162 connected = 1;
163}
164
165struct modes {
166 char *m_name;
167 char *m_mode;
168} modes[] = {
169 { "ascii", "netascii" },
170 { "binary", "octect" },
171 { "mail", "mail" },
172 { 0, 0 }
173};
174
175setmode(argc, argv)
176 char *argv[];
177{
178 register struct modes *p;
179
180 if (argc > 2) {
181 char *sep;
182
183 printf("usage: %s [", argv[0]);
184 sep = " ";
185 for (p = modes; p->m_name; p++) {
186 printf("%s%s", sep, p->m_name);
187 if (*sep == ' ')
188 sep = " | ";
189 }
190 printf(" ]\n");
191 return;
192 }
193 if (argc < 2) {
194 printf("Using %s mode to transfer files.\n", mode);
195 return;
196 }
197 for (p = modes; p->m_name; p++)
198 if (strcmp(argv[1], p->m_name) == 0)
199 break;
200 if (p->m_name)
201 strcpy(mode, p->m_mode);
202 else
203 printf("%s: unknown mode\n", argv[1]);
204}
205
206/*
207 * Send file(s).
208 */
209put(argc, argv)
210 char *argv[];
211{
212 int fd;
213 register int n, addr;
214 register char *cp, *targ;
215
216 if (argc < 2) {
217 strcpy(line, "send ");
218 printf("(file) ");
219 gets(&line[strlen(line)]);
220 makeargv();
221 argc = margc;
222 argv = margv;
223 }
224 if (argc < 2) {
225 putusage(argv[0]);
226 return;
227 }
228 targ = argv[argc - 1];
229 if (index(argv[argc - 1], ':')) {
4d5e33bd
SL
230 char *cp;
231 struct hostent *hp;
c3353d83
SL
232
233 for (n = 1; n < argc - 1; n++)
234 if (index(argv[n], ':')) {
235 putusage(argv[0]);
236 return;
237 }
4d5e33bd
SL
238 cp = argv[argc - 1];
239 targ = index(cp, ':');
c3353d83 240 *targ++ = 0;
4d5e33bd
SL
241 hp = gethostbyname(cp);
242 if (hp == 0) {
243 printf("%s: Unknown host.\n", cp);
c3353d83
SL
244 return;
245 }
de3b21e8 246 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
4d5e33bd 247 sin.sin_family = hp->h_addrtype;
c3353d83 248 connected = 1;
4d5e33bd 249 hostname = hp->h_name;
c3353d83
SL
250 }
251 if (!connected) {
252 printf("No target machine specified.\n");
253 return;
254 }
c3353d83
SL
255 if (argc < 4) {
256 cp = argc == 2 ? tail(targ) : argv[1];
61ad9979 257 fd = open(cp, O_RDONLY);
c3353d83 258 if (fd < 0) {
61ad9979 259 fprintf(stderr, "tftp: "); perror(cp);
c3353d83
SL
260 return;
261 }
262 sendfile(fd, targ);
263 return;
264 }
265 cp = index(targ, '\0');
266 *cp++ = '/';
267 for (n = 1; n < argc - 1; n++) {
268 strcpy(cp, tail(argv[n]));
61ad9979 269 fd = open(argv[n], O_RDONLY);
c3353d83 270 if (fd < 0) {
61ad9979 271 fprintf(stderr, "tftp: "); perror(argv[n]);
c3353d83
SL
272 continue;
273 }
274 sendfile(fd, targ);
275 }
276}
277
278putusage(s)
279 char *s;
280{
281 printf("usage: %s file ... host:target, or\n", s);
282 printf(" %s file ... target (when already connected)\n", s);
283}
284
285/*
286 * Receive file(s).
287 */
288get(argc, argv)
289 char *argv[];
290{
291 int fd;
292 register int n, addr;
293 register char *cp;
294 char *src;
295
296 if (argc < 2) {
297 strcpy(line, "get ");
298 printf("(files) ");
299 gets(&line[strlen(line)]);
300 makeargv();
301 argc = margc;
302 argv = margv;
303 }
304 if (argc < 2) {
305 getusage(argv[0]);
306 return;
307 }
308 if (!connected)
309 for (n = 1; n < argc - 1; n++)
310 if (index(argv[n], ':') == 0) {
311 getusage(argv[0]);
312 return;
313 }
c3353d83
SL
314 for (n = 1; argc == 2 || n < argc - 1; n++) {
315 src = index(argv[n], ':');
316 if (src == NULL)
317 src = argv[n];
318 else {
4d5e33bd
SL
319 struct hostent *hp;
320
c3353d83 321 *src++ = 0;
4d5e33bd
SL
322 hp = gethostbyname(argv[n]);
323 if (hp == 0) {
c3353d83
SL
324 printf("%s: Unknown host.\n", argv[n]);
325 continue;
326 }
de3b21e8 327 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
4d5e33bd 328 sin.sin_family = hp->h_addrtype;
c3353d83 329 connected = 1;
4d5e33bd 330 hostname = hp->h_name;
c3353d83
SL
331 }
332 if (argc < 4) {
333 cp = argc == 3 ? argv[2] : tail(src);
334 fd = creat(cp, 0644);
335 if (fd < 0) {
61ad9979 336 fprintf(stderr, "tftp: "); perror(cp);
c3353d83
SL
337 return;
338 }
339 recvfile(fd, src);
340 break;
341 }
342 cp = index(argv[argc - 1], '\0');
343 *cp++ = '/';
344 strcpy(cp, tail(src));
345 fd = creat(src, 0644);
346 if (fd < 0) {
61ad9979 347 fprintf(stderr, "tftp: "); perror(src);
c3353d83
SL
348 continue;
349 }
350 recvfile(fd, src);
351 }
352}
353
354getusage(s)
355{
356 printf("usage: %s host:file host:file ... file, or\n", s);
357 printf(" %s file file ... file if connected\n", s);
358}
359
61ad9979
SL
360int rexmtval = TIMEOUT;
361
362setrexmt(argc, argv)
363 char *argv[];
364{
365 int t;
366
367 if (argc < 2) {
368 strcpy(line, "Rexmt-timeout ");
369 printf("(value) ");
370 gets(&line[strlen(line)]);
371 makeargv();
372 argc = margc;
373 argv = margv;
374 }
375 if (argc != 2) {
376 printf("usage: %s value\n", argv[0]);
377 return;
378 }
379 t = atoi(argv[1]);
380 if (t < 0)
381 printf("%s: bad value\n", t);
382 else
383 rexmtval = t;
384}
385
386int maxtimeout = 5 * TIMEOUT;
387
388settimeout(argc, argv)
389 char *argv[];
390{
391 int t;
392
393 if (argc < 2) {
394 strcpy(line, "Maximum-timeout ");
395 printf("(value) ");
396 gets(&line[strlen(line)]);
397 makeargv();
398 argc = margc;
399 argv = margv;
400 }
401 if (argc != 2) {
402 printf("usage: %s value\n", argv[0]);
403 return;
404 }
405 t = atoi(argv[1]);
406 if (t < 0)
407 printf("%s: bad value\n", t);
408 else
409 maxtimeout = t;
410}
411
c3353d83
SL
412status(argc, argv)
413 char *argv[];
414{
415 if (connected)
4d5e33bd 416 printf("Connected to %s.\n", hostname);
c3353d83
SL
417 else
418 printf("Not connected.\n");
419 printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
420 verbose ? "on" : "off", trace ? "on" : "off");
61ad9979
SL
421 printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
422 rexmtval, maxtimeout);
c3353d83
SL
423}
424
425intr()
426{
61ad9979 427
c3353d83
SL
428 longjmp(toplevel, -1);
429}
430
431char *
432tail(filename)
433 char *filename;
434{
435 register char *s;
436
437 while (*filename) {
438 s = rindex(filename, '/');
439 if (s == NULL)
440 break;
441 if (s[1])
442 return (s + 1);
443 *s = '\0';
444 }
445 return (filename);
446}
447
448/*
449 * Command parser.
450 */
451command(top)
452 int top;
453{
454 register struct cmd *c;
455
456 if (!top)
457 putchar('\n');
c3353d83
SL
458 for (;;) {
459 printf("%s> ", prompt);
460 if (gets(line) == 0)
61ad9979 461 continue;
c3353d83 462 if (line[0] == 0)
61ad9979 463 continue;
c3353d83
SL
464 makeargv();
465 c = getcmd(margv[0]);
466 if (c == (struct cmd *)-1) {
467 printf("?Ambiguous command\n");
468 continue;
469 }
470 if (c == 0) {
471 printf("?Invalid command\n");
472 continue;
473 }
474 (*c->handler)(margc, margv);
c3353d83 475 }
c3353d83
SL
476}
477
478struct cmd *
479getcmd(name)
480 register char *name;
481{
482 register char *p, *q;
483 register struct cmd *c, *found;
484 register int nmatches, longest;
485
486 longest = 0;
487 nmatches = 0;
488 found = 0;
489 for (c = cmdtab; p = c->name; c++) {
490 for (q = name; *q == *p++; q++)
491 if (*q == 0) /* exact match? */
492 return (c);
493 if (!*q) { /* the name was a prefix */
494 if (q - name > longest) {
495 longest = q - name;
496 nmatches = 1;
497 found = c;
498 } else if (q - name == longest)
499 nmatches++;
500 }
501 }
502 if (nmatches > 1)
503 return ((struct cmd *)-1);
504 return (found);
505}
506
507/*
508 * Slice a string up into argc/argv.
509 */
510makeargv()
511{
512 register char *cp;
513 register char **argp = margv;
514
515 margc = 0;
516 for (cp = line; *cp;) {
517 while (isspace(*cp))
518 cp++;
519 if (*cp == '\0')
520 break;
521 *argp++ = cp;
522 margc += 1;
523 while (*cp != '\0' && !isspace(*cp))
524 cp++;
525 if (*cp == '\0')
526 break;
527 *cp++ = '\0';
528 }
529 *argp++ = 0;
530}
531
532/*VARARGS*/
533quit()
534{
535 exit(0);
536}
537
538/*
539 * Help command.
c3353d83
SL
540 */
541help(argc, argv)
542 int argc;
543 char *argv[];
544{
545 register struct cmd *c;
546
547 if (argc == 1) {
548 printf("Commands may be abbreviated. Commands are:\n\n");
549 for (c = cmdtab; c->name; c++)
550 printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
551 return;
552 }
553 while (--argc > 0) {
554 register char *arg;
555 arg = *++argv;
556 c = getcmd(arg);
557 if (c == (struct cmd *)-1)
558 printf("?Ambiguous help command %s\n", arg);
559 else if (c == (struct cmd *)0)
560 printf("?Invalid help command %s\n", arg);
561 else
562 printf("%s\n", c->help);
563 }
564}
565
566/*
567 * Call routine with argc, argv set from args (terminated by 0).
568 */
569/* VARARGS2 */
570call(routine, args)
571 int (*routine)();
572 int args;
573{
574 register int *argp;
575 register int argc;
576
577 for (argc = 0, argp = &args; *argp++ != 0; argc++)
578 ;
579 (*routine)(argc, &args);
580}
581
582/*VARARGS*/
583settrace()
584{
585 trace = !trace;
586 printf("Packet tracing %s.\n", trace ? "on" : "off");
587}
588
589/*VARARGS*/
590setverbose()
591{
592 verbose = !verbose;
593 printf("Verbose mode %s.\n", verbose ? "on" : "off");
594}