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