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