|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)main.c 4.9 (Berkeley) 7/18/83";
3: #endif
4:
5: /*
6: * FTP User Program -- Command Interface.
7: */
8: #include <sys/param.h>
9: #include <sys/socket.h>
10: #include <sys/ioctl.h>
11:
12: #include <arpa/ftp.h>
13:
14: #include <signal.h>
15: #include <stdio.h>
16: #include <errno.h>
17: #include <ctype.h>
18: #include <netdb.h>
19: #include <pwd.h>
20:
21: #include "ftp_var.h"
22:
23: int intr();
24: int lostpeer();
25: extern char *home;
26:
27: main(argc, argv)
28: char *argv[];
29: {
30: register char *cp;
31: int top;
32: struct passwd *pw;
33: char homedir[MAXPATHLEN];
34:
35: sp = getservbyname("ftp", "tcp");
36: if (sp == 0) {
37: fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
38: exit(1);
39: }
40: doglob = 1;
41: interactive = 1;
42: autologin = 1;
43: argc--, argv++;
44: while (argc > 0 && **argv == '-') {
45: for (cp = *argv + 1; *cp; cp++)
46: switch (*cp) {
47:
48: case 'd':
49: options |= SO_DEBUG;
50: debug++;
51: break;
52:
53: case 'v':
54: verbose++;
55: break;
56:
57: case 't':
58: trace++;
59: break;
60:
61: case 'i':
62: interactive = 0;
63: break;
64:
65: case 'n':
66: autologin = 0;
67: break;
68:
69: case 'g':
70: doglob = 0;
71: break;
72:
73: default:
74: fprintf(stderr,
75: "ftp: %c: unknown option\n", *cp);
76: exit(1);
77: }
78: argc--, argv++;
79: }
80: fromatty = isatty(fileno(stdin));
81: /*
82: * Set up defaults for FTP.
83: */
84: strcpy(typename, "ascii"), type = TYPE_A;
85: strcpy(formname, "non-print"), form = FORM_N;
86: strcpy(modename, "stream"), mode = MODE_S;
87: strcpy(structname, "file"), stru = STRU_F;
88: strcpy(bytename, "8"), bytesize = 8;
89: if (fromatty)
90: verbose++;
91: /*
92: * Set up the home directory in case we're globbing.
93: */
94: pw = getpwnam(getlogin());
95: if (pw == NULL)
96: pw = getpwuid(getuid());
97: if (pw != NULL) {
98: home = homedir;
99: strcpy(home, pw->pw_dir);
100: }
101: if (argc > 0) {
102: if (setjmp(toplevel))
103: exit(0);
104: signal(SIGINT, intr);
105: signal(SIGPIPE, lostpeer);
106: setpeer(argc + 1, argv - 1);
107: }
108: top = setjmp(toplevel) == 0;
109: if (top) {
110: signal(SIGINT, intr);
111: signal(SIGPIPE, lostpeer);
112: }
113: for (;;) {
114: cmdscanner(top);
115: top = 1;
116: }
117: }
118:
119: intr()
120: {
121:
122: longjmp(toplevel, 1);
123: }
124:
125: lostpeer()
126: {
127: extern FILE *cout;
128: extern int data;
129:
130: if (connected) {
131: if (cout != NULL) {
132: shutdown(fileno(cout), 1+1);
133: fclose(cout);
134: cout = NULL;
135: }
136: if (data >= 0) {
137: shutdown(data, 1+1);
138: (void) close(data);
139: data = -1;
140: }
141: connected = 0;
142: }
143: longjmp(toplevel, 1);
144: }
145:
146: char *
147: tail(filename)
148: char *filename;
149: {
150: register char *s;
151:
152: while (*filename) {
153: s = rindex(filename, '/');
154: if (s == NULL)
155: break;
156: if (s[1])
157: return (s + 1);
158: *s = '\0';
159: }
160: return (filename);
161: }
162:
163: /*
164: * Command parser.
165: */
166: cmdscanner(top)
167: int top;
168: {
169: register struct cmd *c;
170: struct cmd *getcmd();
171: extern struct cmd cmdtab[];
172: extern int help();
173:
174: if (!top)
175: putchar('\n');
176: for (;;) {
177: if (fromatty) {
178: printf("ftp> ");
179: fflush(stdout);
180: }
181: if (gets(line) == 0) {
182: if (feof(stdin)) {
183: clearerr(stdin);
184: putchar('\n');
185: }
186: break;
187: }
188: if (line[0] == 0)
189: break;
190: makeargv();
191: c = getcmd(margv[0]);
192: if (c == (struct cmd *)-1) {
193: printf("?Ambiguous command\n");
194: continue;
195: }
196: if (c == 0) {
197: printf("?Invalid command\n");
198: continue;
199: }
200: if (c->c_conn && !connected) {
201: printf ("Not connected.\n");
202: continue;
203: }
204: (*c->c_handler)(margc, margv);
205: if (bell && c->c_bell)
206: putchar(CTRL(g));
207: if (c->c_handler != help)
208: break;
209: }
210: longjmp(toplevel, 0);
211: }
212:
213: struct cmd *
214: getcmd(name)
215: register char *name;
216: {
217: register char *p, *q;
218: register struct cmd *c, *found;
219: register int nmatches, longest;
220:
221: longest = 0;
222: nmatches = 0;
223: found = 0;
224: for (c = cmdtab; p = c->c_name; c++) {
225: for (q = name; *q == *p++; q++)
226: if (*q == 0) /* exact match? */
227: return (c);
228: if (!*q) { /* the name was a prefix */
229: if (q - name > longest) {
230: longest = q - name;
231: nmatches = 1;
232: found = c;
233: } else if (q - name == longest)
234: nmatches++;
235: }
236: }
237: if (nmatches > 1)
238: return ((struct cmd *)-1);
239: return (found);
240: }
241:
242: /*
243: * Slice a string up into argc/argv.
244: */
245: makeargv()
246: {
247: char **argp;
248: char *slurpstring();
249:
250: margc = 0;
251: argp = margv;
252: stringbase = line; /* scan from first of buffer */
253: argbase = argbuf; /* store from first of buffer */
254: while (*argp++ = slurpstring())
255: margc++;
256: }
257:
258: /*
259: * Parse string into argbuf;
260: * implemented with FSM to
261: * handle quoting and strings
262: */
263: char *
264: slurpstring()
265: {
266: int got_one = 0;
267: register char *sb = stringbase;
268: register char *ap = argbase;
269: char *tmp = argbase; /* will return this if token found */
270:
271: if (*sb == '!') { /* recognize ! as a token for shell */
272: stringbase++;
273: return ("!");
274: }
275: S0:
276: switch (*sb) {
277:
278: case '\0':
279: goto OUT;
280:
281: case ' ':
282: case '\t':
283: sb++; goto S0;
284:
285: default:
286: goto S1;
287: }
288:
289: S1:
290: switch (*sb) {
291:
292: case ' ':
293: case '\t':
294: case '\0':
295: goto OUT; /* end of token */
296:
297: case '\\':
298: sb++; goto S2; /* slurp next character */
299:
300: case '"':
301: sb++; goto S3; /* slurp quoted string */
302:
303: default:
304: *ap++ = *sb++; /* add character to token */
305: got_one = 1;
306: goto S1;
307: }
308:
309: S2:
310: switch (*sb) {
311:
312: case '\0':
313: goto OUT;
314:
315: default:
316: *ap++ = *sb++;
317: got_one = 1;
318: goto S1;
319: }
320:
321: S3:
322: switch (*sb) {
323:
324: case '\0':
325: goto OUT;
326:
327: case '"':
328: sb++; goto S1;
329:
330: default:
331: *ap++ = *sb++;
332: got_one = 1;
333: goto S3;
334: }
335:
336: OUT:
337: if (got_one)
338: *ap++ = '\0';
339: argbase = ap; /* update storage pointer */
340: stringbase = sb; /* update scan pointer */
341: if (got_one)
342: return(tmp);
343: return((char *)0);
344: }
345:
346: #define HELPINDENT (sizeof ("directory"))
347:
348: /*
349: * Help command.
350: * Call each command handler with argc == 0 and argv[0] == name.
351: */
352: help(argc, argv)
353: int argc;
354: char *argv[];
355: {
356: register struct cmd *c;
357:
358: if (argc == 1) {
359: register int i, j, w;
360: int columns, width = 0, lines;
361: extern int NCMDS;
362:
363: printf("Commands may be abbreviated. Commands are:\n\n");
364: for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
365: int len = strlen(c->c_name);
366:
367: if (len > width)
368: width = len;
369: }
370: width = (width + 8) &~ 7;
371: columns = 80 / width;
372: if (columns == 0)
373: columns = 1;
374: lines = (NCMDS + columns - 1) / columns;
375: for (i = 0; i < lines; i++) {
376: for (j = 0; j < columns; j++) {
377: c = cmdtab + j * lines + i;
378: printf("%s", c->c_name);
379: if (c + lines >= &cmdtab[NCMDS]) {
380: printf("\n");
381: break;
382: }
383: w = strlen(c->c_name);
384: while (w < width) {
385: w = (w + 8) &~ 7;
386: putchar('\t');
387: }
388: }
389: }
390: return;
391: }
392: while (--argc > 0) {
393: register char *arg;
394: arg = *++argv;
395: c = getcmd(arg);
396: if (c == (struct cmd *)-1)
397: printf("?Ambiguous help command %s\n", arg);
398: else if (c == (struct cmd *)0)
399: printf("?Invalid help command %s\n", arg);
400: else
401: printf("%-*s\t%s\n", HELPINDENT,
402: c->c_name, c->c_help);
403: }
404: }
405:
406: /*
407: * Call routine with argc, argv set from args (terminated by 0).
408: */
409: /* VARARGS2 */
410: call(routine, args)
411: int (*routine)();
412: int args;
413: {
414: register int *argp;
415: register int argc;
416:
417: for (argc = 0, argp = &args; *argp++ != 0; argc++)
418: ;
419: (*routine)(argc, &args);
420: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.