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]
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
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
39 #pragma ident "%Z%%M% %I% %E% SMI"
42 * FTP User Program -- Command Interface.
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);
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] " \
64 main(int argc
, char *argv
[])
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
);
76 (void) fprintf(stderr
, "ftp: memory allocation failed\n");
80 timeoutms
= timeout
= 0;
86 /* by default SYST command will be sent to determine system type */
93 sendport
= -1; /* tri-state variable. start out in "automatic" mode. */
96 while ((c
= getopt(argc
, argv
, GETOPT_STR
)) != EOF
) {
127 /* undocumented option: allows testing of EPRT */
133 if (!isdigit(*optarg
)) {
134 (void) fprintf(stderr
,
135 "ftp: bad timeout: \"%s\"\n", optarg
);
138 timeout
= atoi(optarg
);
139 timeoutms
= timeout
* MILLISEC
;
153 call(setmech
, "ftp", optarg
, 0);
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;
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.
228 pw
= getpwuid(getuid());
231 (void) strcpy(home
, pw
->pw_dir
);
233 if (setjmp(timeralarm
)) {
234 (void) fflush(stdout
);
235 (void) printf("Connection timeout\n");
238 (void) signal(SIGALRM
, timeout_sig
);
244 if (setjmp(toplevel
))
246 (void) signal(SIGINT
, intr
);
247 (void) signal(SIGPIPE
, lostpeer
);
248 nargv
[nargc
++] = "ftp";
249 nargv
[nargc
++] = argv
[0]; /* hostname */
251 nargv
[nargc
++] = argv
[1]; /* port */
253 setpeer(nargc
, nargv
);
255 top
= setjmp(toplevel
) == 0;
257 (void) signal(SIGINT
, intr
);
258 (void) signal(SIGPIPE
, lostpeer
);
270 (void) fprintf(stderr
, "usage: ftp %s\n", USAGE_STR
);
277 /* The test is just to reduce syscalls if timeouts aren't used */
293 longjmp(timeralarm
, 1);
300 longjmp(toplevel
, 1);
307 extern FILE *ctrl_out
;
311 if (ctrl_out
!= NULL
) {
312 (void) shutdown(fileno(ctrl_out
), 1+1);
313 (void) fclose(ctrl_out
);
317 (void) shutdown(data
, 1+1);
323 auth_type
= AUTHTYPE_NONE
;
324 clevel
= dlevel
= PROT_C
;
329 if (ctrl_out
!= NULL
) {
330 (void) shutdown(fileno(ctrl_out
), 1+1);
331 (void) fclose(ctrl_out
);
336 auth_type
= AUTHTYPE_NONE
;
337 clevel
= dlevel
= PROT_C
;
353 (void) putchar('\n');
357 (void) printf("ftp> ");
358 (void) fflush(stdout
);
360 if (fgets(line
, sizeof (line
), stdin
) == 0) {
361 if (feof(stdin
) || ferror(stdin
))
367 /* If not all, just discard rest of line */
368 if (line
[strlen(line
)-1] != '\n') {
369 while (fgetc(stdin
) != '\n' && !feof(stdin
) &&
372 (void) printf("Line too long\n");
375 line
[strlen(line
)-1] = 0;
381 c
= getcmd(margv
[0]);
382 if (c
== (struct cmd
*)-1) {
383 (void) printf("?Ambiguous command\n");
387 (void) printf("?Invalid command\n");
390 if (c
->c_conn
&& !connected
) {
391 (void) printf("Not connected.\n");
395 (*c
->c_handler
)(margc
, margv
);
397 #define CTRL(c) ((c)&037)
400 if (bell
&& c
->c_bell
)
401 (void) putchar(CTRL('g'));
402 if (c
->c_handler
!= help
)
405 (void) signal(SIGINT
, intr
);
406 (void) signal(SIGPIPE
, lostpeer
);
413 struct cmd
*c
, *found
;
414 int nmatches
, longest
;
415 extern struct cmd cmdtab
[];
423 for (c
= cmdtab
; (p
= c
->c_name
) != NULL
; c
++) {
424 for (q
= name
; *q
== *p
++; q
++)
425 if (*q
== 0) /* exact match? */
427 if (!*q
) { /* the name was a prefix */
428 if (q
- name
> longest
) {
432 } else if (q
- name
== longest
)
437 return ((struct cmd
*)-1);
442 * Slice a string up into argc/argv.
452 static int margv_size
;
455 stringbase
= line
; /* scan from first of buffer */
456 argbase
= argbuf
; /* store from first of buffer */
460 margv_size
= MARGV_INC
;
461 if ((margv
= malloc(margv_size
* sizeof (char *))) == NULL
)
462 fatal("Out of memory");
465 while (*argp
++ = slurpstring()) {
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
486 char *sb
= stringbase
;
488 char *tmp
= argbase
; /* will return this if token found */
491 if (*sb
== '!' || *sb
== '$') { /* recognize ! as a token for shell */
492 switch (slrflag
) { /* and $ as token for macro invoke */
496 return ((*sb
== '!') ? "!" : "$");
537 goto OUT
; /* end of token */
540 sb
++; goto S2
; /* slurp next character */
543 sb
++; goto S3
; /* slurp quoted string */
546 if ((len
= mblen(sb
, MB_CUR_MAX
)) <= 0)
562 if ((len
= mblen(sb
, MB_CUR_MAX
)) <= 0)
581 if ((len
= mblen(sb
, MB_CUR_MAX
)) <= 0)
593 argbase
= ap
; /* update storage pointer */
594 stringbase
= sb
; /* update scan pointer */
612 #define HELPINDENT (sizeof ("directory"))
616 * Call each command handler with argc == 0 and argv[0] == name.
619 help(int argc
, char *argv
[])
622 extern struct cmd cmdtab
[];
626 int columns
, width
= 0, lines
;
630 "Commands may be abbreviated. Commands are:\n\n");
631 for (c
= cmdtab
; c
< &cmdtab
[NCMDS
]; c
++) {
632 int len
= strlen(c
->c_name
);
637 width
= (width
+ 8) &~ 7;
638 columns
= 80 / width
;
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
);
653 if (c
+ lines
>= &cmdtab
[NCMDS
]) {
657 w
= strlen(c
->c_name
);
660 (void) putchar('\t');
670 if (c
== (struct cmd
*)-1)
671 (void) printf("?Ambiguous help command %s\n", arg
);
673 (void) printf("?Invalid help command %s\n", arg
);
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).
684 call(void (*routine
)(int argc
, char *argv
[]), ...)
690 va_start(ap
, routine
);
691 while ((argv
[argc
] = va_arg(ap
, char *)) != NULL
)
694 (*routine
)(argc
, argv
);