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