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