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