2 * Copyright (c) 1985, 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * FTP User Program -- Command Interface.
41 RCSID("$Id: main.c,v 1.33.2.1 2003/08/20 16:43:14 lha Exp $");
44 static int version_flag
;
45 static int debug_flag
;
47 struct getargs getargs
[] = {
48 { NULL
, 'd', arg_flag
, &debug_flag
,
50 { NULL
, 'g', arg_negative_flag
, &doglob
,
51 "disables globbing", NULL
},
52 { NULL
, 'i', arg_negative_flag
, &interactive
,
53 "Turn off interactive prompting", NULL
},
54 { NULL
, 'l', arg_negative_flag
, &lineedit
,
55 "Turn off line editing", NULL
},
56 { NULL
, 'n', arg_negative_flag
, &autologin
,
57 "Turn off auto-login", NULL
},
58 { NULL
, 'p', arg_flag
, &passivemode
,
59 "passive mode", NULL
},
60 { NULL
, 't', arg_counter
, &trace
,
61 "Packet tracing", NULL
},
63 { "gss-bindings", 0, arg_negative_flag
, &ftp_do_gss_bindings
,
64 "Use GSS-API bindings", NULL
},
66 { NULL
, 'v', arg_counter
, &verbose
,
68 { NULL
, 'K', arg_negative_flag
, &use_kerberos
,
69 "Disable kerberos authentication", NULL
},
70 { "version", 0, arg_flag
, &version_flag
},
71 { "help", 'h', arg_flag
, &help_flag
},
74 static int num_args
= sizeof(getargs
) / sizeof(getargs
[0]);
79 arg_printusage(getargs
, num_args
, NULL
, "[host [port]]");
84 main(int argc
, char **argv
)
87 struct passwd
*pw
= NULL
;
88 char homedir
[MaxPathLen
];
94 sp
= getservbyname("ftp", "tcp");
96 errx(1, "ftp/tcp: unknown service");
101 passivemode
= 0; /* passive mode not active */
104 ftp_do_gss_bindings
= 1;
107 if(getarg(getargs
, num_args
, argc
, argv
, &optind
))
124 fromatty
= isatty(fileno(stdin
));
127 cpend
= 0; /* no pending replies */
128 proxy
= 0; /* proxy not active */
129 crflag
= 1; /* strip c.r. on ascii gets */
130 sendport
= -1; /* not using ports */
132 * Set up the home directory in case we're globbing.
134 pw
= k_getpwuid(getuid());
136 strlcpy(homedir
, pw
->pw_dir
, sizeof(homedir
));
142 if (setjmp(toplevel
))
144 signal(SIGINT
, intr
);
145 signal(SIGPIPE
, lostpeer
);
146 xargv
[0] = (char*)getprogname();
151 setpeer(argc
+1, xargv
);
153 if(setjmp(toplevel
) == 0)
158 signal(SIGINT
, intr
);
159 signal(SIGPIPE
, lostpeer
);
171 longjmp(toplevel
, 1);
184 shutdown(fileno(cout
), SHUT_RDWR
);
189 shutdown(data
, SHUT_RDWR
);
198 shutdown(fileno(cout
), SHUT_RDWR
);
218 s = strrchr(filename, '/');
230 simple_readline(char *prompt
)
233 printf ("%s", prompt
);
235 if(fgets(buf
, sizeof(buf
), stdin
) == NULL
)
237 if (buf
[strlen(buf
) - 1] == '\n')
238 buf
[strlen(buf
) - 1] = '\0';
242 #ifndef HAVE_READLINE
245 readline(char *prompt
)
247 return simple_readline (prompt
);
257 /* These should not really be here */
259 char *readline(char *);
260 void add_history(char *);
279 p
= readline("ftp> ");
281 p
= simple_readline("ftp> ");
286 strlcpy(line
, p
, sizeof(line
));
291 if (fgets(line
, sizeof line
, stdin
) == NULL
)
294 /* XXX will break on long lines */
298 if (line
[--l
] == '\n') {
302 } else if (l
== sizeof(line
) - 2) {
303 printf("sorry, input line too long\n");
304 while ((l
= getchar()) != '\n' && l
!= EOF
)
307 } /* else it was a line without a newline */
312 c
= getcmd(margv
[0]);
313 if (c
== (struct cmd
*)-1) {
314 printf("?Ambiguous command\n");
318 printf("?Invalid command\n");
321 if (c
->c_conn
&& !connected
) {
322 printf("Not connected.\n");
325 (*c
->c_handler
)(margc
, margv
);
326 if (bell
&& c
->c_bell
)
328 if (c
->c_handler
!= help
)
331 signal(SIGINT
, intr
);
332 signal(SIGPIPE
, lostpeer
);
339 struct cmd
*c
, *found
;
340 int nmatches
, longest
;
345 for (c
= cmdtab
; (p
= c
->c_name
); c
++) {
346 for (q
= name
; *q
== *p
++; q
++)
347 if (*q
== 0) /* exact match? */
349 if (!*q
) { /* the name was a prefix */
350 if (q
- name
> longest
) {
354 } else if (q
- name
== longest
)
359 return ((struct cmd
*)-1);
364 * Slice a string up into argc/argv.
375 stringbase
= line
; /* scan from first of buffer */
376 argbase
= argbuf
; /* store from first of buffer */
378 for (margc
= 0; ; margc
++) {
379 /* Expand array if necessary */
380 if (margc
== margvlen
) {
383 margv
= (margvlen
== 0)
384 ? (char **)malloc(20 * sizeof(char *))
385 : (char **)realloc(margv
,
386 (margvlen
+ 20)*sizeof(char *));
388 errx(1, "cannot realloc argv array");
389 for(i
= margvlen
; i
< margvlen
+ 20; ++i
)
392 argp
= margv
+ margc
;
395 if ((*argp
++ = slurpstring()) == NULL
)
402 * Parse string into argbuf;
403 * implemented with FSM to
404 * handle quoting and strings
410 char *sb
= stringbase
;
412 char *tmp
= argbase
; /* will return this if token found */
414 if (*sb
== '!' || *sb
== '$') { /* recognize ! as a token for shell */
415 switch (slrflag
) { /* and $ as token for macro invoke */
419 return ((*sb
== '!') ? "!" : "$");
461 goto OUT
; /* end of token */
464 sb
++; goto S2
; /* slurp next character */
467 sb
++; goto S3
; /* slurp quoted string */
470 *ap
++ = *sb
++; /* add character to token */
505 argbase
= ap
; /* update storage pointer */
506 stringbase
= sb
; /* update scan pointer */
524 #define HELPINDENT ((int) sizeof ("directory"))
528 * Call each command handler with argc == 0 and argv[0] == name.
531 help(int argc
, char **argv
)
537 int columns
, width
= 0, lines
;
539 printf("Commands may be abbreviated. Commands are:\n\n");
540 for (c
= cmdtab
; c
< &cmdtab
[NCMDS
]; c
++) {
541 int len
= strlen(c
->c_name
);
546 width
= (width
+ 8) &~ 7;
547 columns
= 80 / width
;
550 lines
= (NCMDS
+ columns
- 1) / columns
;
551 for (i
= 0; i
< lines
; i
++) {
552 for (j
= 0; j
< columns
; j
++) {
553 c
= cmdtab
+ j
* lines
+ i
;
554 if (c
->c_name
&& (!proxy
|| c
->c_proxy
)) {
555 printf("%s", c
->c_name
);
557 else if (c
->c_name
) {
558 for (k
=0; k
< strlen(c
->c_name
); k
++) {
562 if (c
+ lines
>= &cmdtab
[NCMDS
]) {
566 w
= strlen(c
->c_name
);
579 if (c
== (struct cmd
*)-1)
580 printf("?Ambiguous help command %s\n", arg
);
581 else if (c
== (struct cmd
*)0)
582 printf("?Invalid help command %s\n", arg
);
584 printf("%-*s\t%s\n", HELPINDENT
,
585 c
->c_name
, c
->c_help
);