dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / ftp / main.c
blob114d0acf64239f43032d7390294d65b924f76419
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
39 #pragma ident "%Z%%M% %I% %E% SMI"
42 * FTP User Program -- Command Interface.
44 #define EXTERN
45 #include "ftp_var.h"
46 #include <deflt.h> /* macros that make using libcmd easier */
48 static void usage(void);
49 static void timeout_sig(int sig);
50 static void cmdscanner(int top);
51 static void intr(int sig);
52 static char *slurpstring(void);
53 extern int use_eprt;
55 boolean_t ls_invokes_NLST = B_TRUE;
57 #include <gssapi/gssapi.h>
58 #include <gssapi/gssapi_ext.h>
59 #define GETOPT_STR "dginpstvET:axfm:"
60 #define USAGE_STR "[-adfginpstvx] [-m mech] [-T timeout] " \
61 "[hostname [port]]"
63 int
64 main(int argc, char *argv[])
66 char *cp;
67 int c, top;
68 struct passwd *pw = NULL;
69 char homedir[MAXPATHLEN];
70 char *temp_string = NULL;
72 (void) setlocale(LC_ALL, "");
74 buf = (char *)memalign(getpagesize(), FTPBUFSIZ);
75 if (buf == NULL) {
76 (void) fprintf(stderr, "ftp: memory allocation failed\n");
77 return (1);
80 timeoutms = timeout = 0;
81 doglob = 1;
82 interactive = 1;
83 autologin = 1;
85 autoauth = 0;
86 /* by default SYST command will be sent to determine system type */
87 skipsyst = 0;
88 fflag = 0;
89 autoencrypt = 0;
90 goteof = 0;
91 mechstr[0] = '\0';
93 sendport = -1; /* tri-state variable. start out in "automatic" mode. */
94 passivemode = 0;
96 while ((c = getopt(argc, argv, GETOPT_STR)) != EOF) {
97 switch (c) {
98 case 'd':
99 options |= SO_DEBUG;
100 debug++;
101 break;
103 case 'g':
104 doglob = 0;
105 break;
107 case 'i':
108 interactive = 0;
109 break;
111 case 'n':
112 autologin = 0;
113 break;
115 case 'p':
116 passivemode = 1;
117 break;
119 case 't':
120 trace++;
121 break;
123 case 'v':
124 verbose++;
125 break;
127 /* undocumented option: allows testing of EPRT */
128 case 'E':
129 use_eprt = 1;
130 break;
132 case 'T':
133 if (!isdigit(*optarg)) {
134 (void) fprintf(stderr,
135 "ftp: bad timeout: \"%s\"\n", optarg);
136 break;
138 timeout = atoi(optarg);
139 timeoutms = timeout * MILLISEC;
140 break;
142 case 'a':
143 autoauth = 1;
144 break;
146 case 'f':
147 autoauth = 1;
148 fflag = 1;
149 break;
151 case 'm':
152 autoauth = 1;
153 call(setmech, "ftp", optarg, 0);
154 if (code != 0)
155 exit(1);
156 break;
158 case 'x':
159 autoauth = 1;
160 autoencrypt = 1;
161 break;
163 case 's':
164 skipsyst = 1;
165 break;
167 case '?':
168 default:
169 usage();
172 argc -= optind;
173 argv += optind;
175 if (argc > 2)
176 usage();
178 fromatty = isatty(fileno(stdin));
180 * Scan env, then DEFAULTFTPFILE
181 * for FTP_LS_SENDS_NLST
183 temp_string = getenv("FTP_LS_SENDS_NLST");
184 if (temp_string == NULL) { /* env var not set */
185 if (defopen(DEFAULTFTPFILE) == 0) {
187 * turn off case sensitivity
189 int flags = defcntl(DC_GETFLAGS, 0);
191 TURNOFF(flags, DC_CASE);
192 (void) defcntl(DC_SETFLAGS, flags);
194 temp_string = defread("FTP_LS_SENDS_NLST=");
195 (void) defopen(NULL); /* close default file */
198 if (temp_string != NULL &&
199 strncasecmp(temp_string, "n", 1) == 0)
200 ls_invokes_NLST = B_FALSE;
203 * Set up defaults for FTP.
205 (void) strcpy(typename, "ascii"), type = TYPE_A;
206 (void) strcpy(formname, "non-print"), form = FORM_N;
207 (void) strcpy(modename, "stream"), mode = MODE_S;
208 (void) strcpy(structname, "file"), stru = STRU_F;
209 (void) strcpy(bytename, "8"), bytesize = 8;
210 if (fromatty)
211 verbose++;
212 cpend = 0; /* no pending replies */
213 proxy = 0; /* proxy not active */
214 crflag = 1; /* strip c.r. on ascii gets */
216 if (mechstr[0] == '\0') {
217 strlcpy(mechstr, FTP_DEF_MECH, MECH_SZ);
221 * Set up the home directory in case we're globbing.
223 cp = getlogin();
224 if (cp != NULL) {
225 pw = getpwnam(cp);
227 if (pw == NULL)
228 pw = getpwuid(getuid());
229 if (pw != NULL) {
230 home = homedir;
231 (void) strcpy(home, pw->pw_dir);
233 if (setjmp(timeralarm)) {
234 (void) fflush(stdout);
235 (void) printf("Connection timeout\n");
236 exit(1);
238 (void) signal(SIGALRM, timeout_sig);
239 reset_timer();
240 if (argc > 0) {
241 int nargc = 0;
242 char *nargv[4];
244 if (setjmp(toplevel))
245 return (0);
246 (void) signal(SIGINT, intr);
247 (void) signal(SIGPIPE, lostpeer);
248 nargv[nargc++] = "ftp";
249 nargv[nargc++] = argv[0]; /* hostname */
250 if (argc > 1)
251 nargv[nargc++] = argv[1]; /* port */
252 nargv[nargc] = NULL;
253 setpeer(nargc, nargv);
255 top = setjmp(toplevel) == 0;
256 if (top) {
257 (void) signal(SIGINT, intr);
258 (void) signal(SIGPIPE, lostpeer);
261 for (;;) {
262 cmdscanner(top);
263 top = 1;
267 static void
268 usage(void)
270 (void) fprintf(stderr, "usage: ftp %s\n", USAGE_STR);
271 exit(1);
274 void
275 reset_timer()
277 /* The test is just to reduce syscalls if timeouts aren't used */
278 if (timeout)
279 alarm(timeout);
282 void
283 stop_timer()
285 if (timeout)
286 alarm(0);
289 /*ARGSUSED*/
290 static void
291 timeout_sig(int sig)
293 longjmp(timeralarm, 1);
296 /*ARGSUSED*/
297 static void
298 intr(int sig)
300 longjmp(toplevel, 1);
303 /*ARGSUSED*/
304 void
305 lostpeer(int sig)
307 extern FILE *ctrl_out;
308 extern int data;
310 if (connected) {
311 if (ctrl_out != NULL) {
312 (void) shutdown(fileno(ctrl_out), 1+1);
313 (void) fclose(ctrl_out);
314 ctrl_out = NULL;
316 if (data >= 0) {
317 (void) shutdown(data, 1+1);
318 (void) close(data);
319 data = -1;
321 connected = 0;
323 auth_type = AUTHTYPE_NONE;
324 clevel = dlevel = PROT_C;
325 goteof = 0;
327 pswitch(1);
328 if (connected) {
329 if (ctrl_out != NULL) {
330 (void) shutdown(fileno(ctrl_out), 1+1);
331 (void) fclose(ctrl_out);
332 ctrl_out = NULL;
334 connected = 0;
336 auth_type = AUTHTYPE_NONE;
337 clevel = dlevel = PROT_C;
338 goteof = 0;
340 proxflag = 0;
341 pswitch(0);
345 * Command parser.
347 static void
348 cmdscanner(int top)
350 struct cmd *c;
352 if (!top)
353 (void) putchar('\n');
354 for (;;) {
355 stop_timer();
356 if (fromatty) {
357 (void) printf("ftp> ");
358 (void) fflush(stdout);
360 if (fgets(line, sizeof (line), stdin) == 0) {
361 if (feof(stdin) || ferror(stdin))
362 quit(0, NULL);
363 break;
365 if (line[0] == 0)
366 break;
367 /* If not all, just discard rest of line */
368 if (line[strlen(line)-1] != '\n') {
369 while (fgetc(stdin) != '\n' && !feof(stdin) &&
370 !ferror(stdin))
372 (void) printf("Line too long\n");
373 continue;
374 } else
375 line[strlen(line)-1] = 0;
377 makeargv();
378 if (margc == 0) {
379 continue;
381 c = getcmd(margv[0]);
382 if (c == (struct cmd *)-1) {
383 (void) printf("?Ambiguous command\n");
384 continue;
386 if (c == 0) {
387 (void) printf("?Invalid command\n");
388 continue;
390 if (c->c_conn && !connected) {
391 (void) printf("Not connected.\n");
392 continue;
394 reset_timer();
395 (*c->c_handler)(margc, margv);
396 #ifndef CTRL
397 #define CTRL(c) ((c)&037)
398 #endif
399 stop_timer();
400 if (bell && c->c_bell)
401 (void) putchar(CTRL('g'));
402 if (c->c_handler != help)
403 break;
405 (void) signal(SIGINT, intr);
406 (void) signal(SIGPIPE, lostpeer);
409 struct cmd *
410 getcmd(char *name)
412 char *p, *q;
413 struct cmd *c, *found;
414 int nmatches, longest;
415 extern struct cmd cmdtab[];
417 if (name == NULL)
418 return (0);
420 longest = 0;
421 nmatches = 0;
422 found = 0;
423 for (c = cmdtab; (p = c->c_name) != NULL; c++) {
424 for (q = name; *q == *p++; q++)
425 if (*q == 0) /* exact match? */
426 return (c);
427 if (!*q) { /* the name was a prefix */
428 if (q - name > longest) {
429 longest = q - name;
430 nmatches = 1;
431 found = c;
432 } else if (q - name == longest)
433 nmatches++;
436 if (nmatches > 1)
437 return ((struct cmd *)-1);
438 return (found);
442 * Slice a string up into argc/argv.
445 static int slrflag;
446 #define MARGV_INC 20
448 void
449 makeargv(void)
451 char **argp;
452 static int margv_size;
454 margc = 0;
455 stringbase = line; /* scan from first of buffer */
456 argbase = argbuf; /* store from first of buffer */
457 slrflag = 0;
459 if (!margv) {
460 margv_size = MARGV_INC;
461 if ((margv = malloc(margv_size * sizeof (char *))) == NULL)
462 fatal("Out of memory");
464 argp = margv;
465 while (*argp++ = slurpstring()) {
466 margc++;
467 if (margc == margv_size) {
468 margv_size += MARGV_INC;
469 if ((margv = reallocarray(margv, margv_size,
470 sizeof (char *))) == NULL)
471 fatal("Out of memory");
472 argp = margv + margc;
478 * Parse string into argbuf;
479 * implemented with FSM to
480 * handle quoting and strings
482 static char *
483 slurpstring(void)
485 int got_one = 0;
486 char *sb = stringbase;
487 char *ap = argbase;
488 char *tmp = argbase; /* will return this if token found */
489 int len;
491 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
492 switch (slrflag) { /* and $ as token for macro invoke */
493 case 0:
494 slrflag++;
495 stringbase++;
496 return ((*sb == '!') ? "!" : "$");
497 case 1:
498 slrflag++;
499 altarg = stringbase;
500 break;
501 default:
502 break;
507 switch (*sb) {
509 case '\0':
510 goto OUT;
512 case ' ':
513 case '\t':
514 sb++; goto S0;
516 default:
517 switch (slrflag) {
518 case 0:
519 slrflag++;
520 break;
521 case 1:
522 slrflag++;
523 altarg = sb;
524 break;
525 default:
526 break;
528 goto S1;
532 switch (*sb) {
534 case ' ':
535 case '\t':
536 case '\0':
537 goto OUT; /* end of token */
539 case '\\':
540 sb++; goto S2; /* slurp next character */
542 case '"':
543 sb++; goto S3; /* slurp quoted string */
545 default:
546 if ((len = mblen(sb, MB_CUR_MAX)) <= 0)
547 len = 1;
548 memcpy(ap, sb, len);
549 ap += len;
550 sb += len;
551 got_one = 1;
552 goto S1;
556 switch (*sb) {
558 case '\0':
559 goto OUT;
561 default:
562 if ((len = mblen(sb, MB_CUR_MAX)) <= 0)
563 len = 1;
564 memcpy(ap, sb, len);
565 ap += len;
566 sb += len;
567 got_one = 1;
568 goto S1;
572 switch (*sb) {
574 case '\0':
575 goto OUT;
577 case '"':
578 sb++; goto S1;
580 default:
581 if ((len = mblen(sb, MB_CUR_MAX)) <= 0)
582 len = 1;
583 memcpy(ap, sb, len);
584 ap += len;
585 sb += len;
586 got_one = 1;
587 goto S3;
590 OUT:
591 if (got_one)
592 *ap++ = '\0';
593 argbase = ap; /* update storage pointer */
594 stringbase = sb; /* update scan pointer */
595 if (got_one) {
596 return (tmp);
598 switch (slrflag) {
599 case 0:
600 slrflag++;
601 break;
602 case 1:
603 slrflag++;
604 altarg = NULL;
605 break;
606 default:
607 break;
609 return (NULL);
612 #define HELPINDENT (sizeof ("directory"))
615 * Help command.
616 * Call each command handler with argc == 0 and argv[0] == name.
618 void
619 help(int argc, char *argv[])
621 struct cmd *c;
622 extern struct cmd cmdtab[];
624 if (argc == 1) {
625 int i, j, w, k;
626 int columns, width = 0, lines;
627 extern int NCMDS;
629 (void) printf(
630 "Commands may be abbreviated. Commands are:\n\n");
631 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
632 int len = strlen(c->c_name);
634 if (len > width)
635 width = len;
637 width = (width + 8) &~ 7;
638 columns = 80 / width;
639 if (columns == 0)
640 columns = 1;
641 lines = (NCMDS + columns - 1) / columns;
642 for (i = 0; i < lines; i++) {
643 for (j = 0; j < columns; j++) {
644 c = cmdtab + j * lines + i;
645 if (c->c_name && (!proxy || c->c_proxy)) {
646 (void) printf("%s", c->c_name);
647 } else if (c->c_name) {
648 for (k = 0; k < strlen(c->c_name);
649 k++) {
650 (void) putchar(' ');
653 if (c + lines >= &cmdtab[NCMDS]) {
654 (void) printf("\n");
655 break;
657 w = strlen(c->c_name);
658 while (w < width) {
659 w = (w + 8) &~ 7;
660 (void) putchar('\t');
664 return;
666 while (--argc > 0) {
667 char *arg;
668 arg = *++argv;
669 c = getcmd(arg);
670 if (c == (struct cmd *)-1)
671 (void) printf("?Ambiguous help command %s\n", arg);
672 else if (c == NULL)
673 (void) printf("?Invalid help command %s\n", arg);
674 else
675 (void) printf("%-*s\t%s\n", HELPINDENT,
676 c->c_name, c->c_help);
681 * Call routine with argc, argv set from args (terminated by 0).
683 void
684 call(void (*routine)(int argc, char *argv[]), ...)
686 va_list ap;
687 char *argv[10];
688 int argc = 0;
690 va_start(ap, routine);
691 while ((argv[argc] = va_arg(ap, char *)) != NULL)
692 argc++;
693 va_end(ap);
694 (*routine)(argc, argv);