main.c revision 1.6 1 /*
2 * Copyright (c) 1985, 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1985, 1989, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 4/3/94";*/
42 static char *rcsid = "$Id: main.c,v 1.6 1994/08/31 21:32:33 mycroft Exp $";
43 #endif /* not lint */
44
45 /*
46 * FTP User Program -- Command Interface.
47 */
48 /*#include <sys/ioctl.h>*/
49 #include <sys/types.h>
50 #include <sys/socket.h>
51
52 #include <arpa/ftp.h>
53
54 #include <ctype.h>
55 #include <err.h>
56 #include <netdb.h>
57 #include <pwd.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62
63 #include "ftp_var.h"
64
65 int
66 main(argc, argv)
67 int argc;
68 char *argv[];
69 {
70 int ch, top;
71 struct passwd *pw = NULL;
72 char *cp, homedir[MAXPATHLEN];
73
74 sp = getservbyname("ftp", "tcp");
75 if (sp == 0)
76 errx(1, "ftp/tcp: unknown service");
77 doglob = 1;
78 interactive = 1;
79 autologin = 1;
80
81 while ((ch = getopt(argc, argv, "dgintv")) != -1) {
82 switch (ch) {
83 case 'd':
84 options |= SO_DEBUG;
85 debug++;
86 break;
87
88 case 'g':
89 doglob = 0;
90 break;
91
92 case 'i':
93 interactive = 0;
94 break;
95
96 case 'n':
97 autologin = 0;
98 break;
99
100 case 't':
101 trace++;
102 break;
103
104 case 'v':
105 verbose++;
106 break;
107
108 default:
109 (void)fprintf(stderr,
110 "usage: ftp [-dgintv] [host [port]]\n");
111 exit(1);
112 }
113 }
114 argc -= optind;
115 argv += optind;
116
117 fromatty = isatty(fileno(stdin));
118 if (fromatty)
119 verbose++;
120 cpend = 0; /* no pending replies */
121 proxy = 0; /* proxy not active */
122 passivemode = 0; /* passive mode not active */
123 crflag = 1; /* strip c.r. on ascii gets */
124 sendport = -1; /* not using ports */
125 /*
126 * Set up the home directory in case we're globbing.
127 */
128 cp = getlogin();
129 if (cp != NULL) {
130 pw = getpwnam(cp);
131 }
132 if (pw == NULL)
133 pw = getpwuid(getuid());
134 if (pw != NULL) {
135 home = homedir;
136 (void) strcpy(home, pw->pw_dir);
137 }
138 if (argc > 0) {
139 char *xargv[5];
140 extern char *__progname;
141
142 if (setjmp(toplevel))
143 exit(0);
144 (void) signal(SIGINT, intr);
145 (void) signal(SIGPIPE, lostpeer);
146 xargv[0] = __progname;
147 xargv[1] = argv[0];
148 xargv[2] = argv[1];
149 xargv[3] = argv[2];
150 xargv[4] = NULL;
151 setpeer(argc+1, xargv);
152 }
153 top = setjmp(toplevel) == 0;
154 if (top) {
155 (void) signal(SIGINT, intr);
156 (void) signal(SIGPIPE, lostpeer);
157 }
158 for (;;) {
159 cmdscanner(top);
160 top = 1;
161 }
162 }
163
164 void
165 intr()
166 {
167
168 longjmp(toplevel, 1);
169 }
170
171 void
172 lostpeer()
173 {
174
175 if (connected) {
176 if (cout != NULL) {
177 (void) shutdown(fileno(cout), 1+1);
178 (void) fclose(cout);
179 cout = NULL;
180 }
181 if (data >= 0) {
182 (void) shutdown(data, 1+1);
183 (void) close(data);
184 data = -1;
185 }
186 connected = 0;
187 }
188 pswitch(1);
189 if (connected) {
190 if (cout != NULL) {
191 (void) shutdown(fileno(cout), 1+1);
192 (void) fclose(cout);
193 cout = NULL;
194 }
195 connected = 0;
196 }
197 proxflag = 0;
198 pswitch(0);
199 }
200
201 /*
202 char *
203 tail(filename)
204 char *filename;
205 {
206 char *s;
207
208 while (*filename) {
209 s = strrchr(filename, '/');
210 if (s == NULL)
211 break;
212 if (s[1])
213 return (s + 1);
214 *s = '\0';
215 }
216 return (filename);
217 }
218 */
219
220 /*
221 * Command parser.
222 */
223 void
224 cmdscanner(top)
225 int top;
226 {
227 struct cmd *c;
228 int l;
229
230 if (!top)
231 (void) putchar('\n');
232 for (;;) {
233 if (fromatty) {
234 printf("ftp> ");
235 (void) fflush(stdout);
236 }
237 if (fgets(line, sizeof line, stdin) == NULL)
238 quit(0, 0);
239 l = strlen(line);
240 if (l == 0)
241 break;
242 if (line[--l] == '\n') {
243 if (l == 0)
244 break;
245 line[l] = '\0';
246 } else if (l == sizeof(line) - 2) {
247 printf("sorry, input line too long\n");
248 while ((l = getchar()) != '\n' && l != EOF)
249 /* void */;
250 break;
251 } /* else it was a line without a newline */
252 makeargv();
253 if (margc == 0) {
254 continue;
255 }
256 c = getcmd(margv[0]);
257 if (c == (struct cmd *)-1) {
258 printf("?Ambiguous command\n");
259 continue;
260 }
261 if (c == 0) {
262 printf("?Invalid command\n");
263 continue;
264 }
265 if (c->c_conn && !connected) {
266 printf("Not connected.\n");
267 continue;
268 }
269 (*c->c_handler)(margc, margv);
270 if (bell && c->c_bell)
271 (void) putchar('\007');
272 if (c->c_handler != help)
273 break;
274 }
275 (void) signal(SIGINT, intr);
276 (void) signal(SIGPIPE, lostpeer);
277 }
278
279 struct cmd *
280 getcmd(name)
281 char *name;
282 {
283 char *p, *q;
284 struct cmd *c, *found;
285 int nmatches, longest;
286
287 longest = 0;
288 nmatches = 0;
289 found = 0;
290 for (c = cmdtab; p = c->c_name; c++) {
291 for (q = name; *q == *p++; q++)
292 if (*q == 0) /* exact match? */
293 return (c);
294 if (!*q) { /* the name was a prefix */
295 if (q - name > longest) {
296 longest = q - name;
297 nmatches = 1;
298 found = c;
299 } else if (q - name == longest)
300 nmatches++;
301 }
302 }
303 if (nmatches > 1)
304 return ((struct cmd *)-1);
305 return (found);
306 }
307
308 /*
309 * Slice a string up into argc/argv.
310 */
311
312 int slrflag;
313
314 void
315 makeargv()
316 {
317 char **argp;
318
319 margc = 0;
320 argp = margv;
321 stringbase = line; /* scan from first of buffer */
322 argbase = argbuf; /* store from first of buffer */
323 slrflag = 0;
324 while (*argp++ = slurpstring())
325 margc++;
326 }
327
328 /*
329 * Parse string into argbuf;
330 * implemented with FSM to
331 * handle quoting and strings
332 */
333 char *
334 slurpstring()
335 {
336 int got_one = 0;
337 char *sb = stringbase;
338 char *ap = argbase;
339 char *tmp = argbase; /* will return this if token found */
340
341 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
342 switch (slrflag) { /* and $ as token for macro invoke */
343 case 0:
344 slrflag++;
345 stringbase++;
346 return ((*sb == '!') ? "!" : "$");
347 /* NOTREACHED */
348 case 1:
349 slrflag++;
350 altarg = stringbase;
351 break;
352 default:
353 break;
354 }
355 }
356
357 S0:
358 switch (*sb) {
359
360 case '\0':
361 goto OUT;
362
363 case ' ':
364 case '\t':
365 sb++; goto S0;
366
367 default:
368 switch (slrflag) {
369 case 0:
370 slrflag++;
371 break;
372 case 1:
373 slrflag++;
374 altarg = sb;
375 break;
376 default:
377 break;
378 }
379 goto S1;
380 }
381
382 S1:
383 switch (*sb) {
384
385 case ' ':
386 case '\t':
387 case '\0':
388 goto OUT; /* end of token */
389
390 case '\\':
391 sb++; goto S2; /* slurp next character */
392
393 case '"':
394 sb++; goto S3; /* slurp quoted string */
395
396 default:
397 *ap++ = *sb++; /* add character to token */
398 got_one = 1;
399 goto S1;
400 }
401
402 S2:
403 switch (*sb) {
404
405 case '\0':
406 goto OUT;
407
408 default:
409 *ap++ = *sb++;
410 got_one = 1;
411 goto S1;
412 }
413
414 S3:
415 switch (*sb) {
416
417 case '\0':
418 goto OUT;
419
420 case '"':
421 sb++; goto S1;
422
423 default:
424 *ap++ = *sb++;
425 got_one = 1;
426 goto S3;
427 }
428
429 OUT:
430 if (got_one)
431 *ap++ = '\0';
432 argbase = ap; /* update storage pointer */
433 stringbase = sb; /* update scan pointer */
434 if (got_one) {
435 return (tmp);
436 }
437 switch (slrflag) {
438 case 0:
439 slrflag++;
440 break;
441 case 1:
442 slrflag++;
443 altarg = (char *) 0;
444 break;
445 default:
446 break;
447 }
448 return ((char *)0);
449 }
450
451 #define HELPINDENT ((int) sizeof ("directory"))
452
453 /*
454 * Help command.
455 * Call each command handler with argc == 0 and argv[0] == name.
456 */
457 void
458 help(argc, argv)
459 int argc;
460 char *argv[];
461 {
462 struct cmd *c;
463
464 if (argc == 1) {
465 int i, j, w, k;
466 int columns, width = 0, lines;
467
468 printf("Commands may be abbreviated. Commands are:\n\n");
469 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
470 int len = strlen(c->c_name);
471
472 if (len > width)
473 width = len;
474 }
475 width = (width + 8) &~ 7;
476 columns = 80 / width;
477 if (columns == 0)
478 columns = 1;
479 lines = (NCMDS + columns - 1) / columns;
480 for (i = 0; i < lines; i++) {
481 for (j = 0; j < columns; j++) {
482 c = cmdtab + j * lines + i;
483 if (c->c_name && (!proxy || c->c_proxy)) {
484 printf("%s", c->c_name);
485 }
486 else if (c->c_name) {
487 for (k=0; k < strlen(c->c_name); k++) {
488 (void) putchar(' ');
489 }
490 }
491 if (c + lines >= &cmdtab[NCMDS]) {
492 printf("\n");
493 break;
494 }
495 w = strlen(c->c_name);
496 while (w < width) {
497 w = (w + 8) &~ 7;
498 (void) putchar('\t');
499 }
500 }
501 }
502 return;
503 }
504 while (--argc > 0) {
505 char *arg;
506 arg = *++argv;
507 c = getcmd(arg);
508 if (c == (struct cmd *)-1)
509 printf("?Ambiguous help command %s\n", arg);
510 else if (c == (struct cmd *)0)
511 printf("?Invalid help command %s\n", arg);
512 else
513 printf("%-*s\t%s\n", HELPINDENT,
514 c->c_name, c->c_help);
515 }
516 }
517