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