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