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