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