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