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