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.32 2002/08/23 19:11:03 assar 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, 'p', arg_flag, &passivemode,
57 "passive mode", NULL},
58 { NULL, 't', arg_counter, &trace,
59 "Packet tracing", NULL},
60 { NULL, 'v', arg_counter, &verbose,
62 { NULL, 'K', arg_negative_flag, &use_kerberos,
63 "Disable kerberos authentication", NULL},
64 { "version", 0, arg_flag, &version_flag },
65 { "help", 'h', arg_flag, &help_flag },
68 static int num_args = sizeof(getargs) / sizeof(getargs[0]);
73 arg_printusage(getargs, num_args, NULL, "[host [port]]");
78 main(int argc, char **argv)
81 struct passwd *pw = NULL;
82 char homedir[MaxPathLen];
88 sp = getservbyname("ftp", "tcp");
90 errx(1, "ftp/tcp: unknown service");
95 passivemode = 0; /* passive mode not active */
98 if(getarg(getargs, num_args, argc, argv, &optind))
115 fromatty = isatty(fileno(stdin));
118 cpend = 0; /* no pending replies */
119 proxy = 0; /* proxy not active */
120 crflag = 1; /* strip c.r. on ascii gets */
121 sendport = -1; /* not using ports */
123 * Set up the home directory in case we're globbing.
125 pw = k_getpwuid(getuid());
127 strlcpy(homedir, pw->pw_dir, sizeof(homedir));
133 if (setjmp(toplevel))
135 signal(SIGINT, intr);
136 signal(SIGPIPE, lostpeer);
137 xargv[0] = (char*)getprogname();
142 setpeer(argc+1, xargv);
144 if(setjmp(toplevel) == 0)
149 signal(SIGINT, intr);
150 signal(SIGPIPE, lostpeer);
162 longjmp(toplevel, 1);
175 shutdown(fileno(cout), SHUT_RDWR);
180 shutdown(data, SHUT_RDWR);
189 shutdown(fileno(cout), SHUT_RDWR);
209 s = strrchr(filename, '/');
221 simple_readline(char *prompt)
224 printf ("%s", prompt);
226 if(fgets(buf, sizeof(buf), stdin) == NULL)
228 if (buf[strlen(buf) - 1] == '\n')
229 buf[strlen(buf) - 1] = '\0';
233 #ifndef HAVE_READLINE
236 readline(char *prompt)
238 return simple_readline (prompt);
248 /* These should not really be here */
250 char *readline(char *);
251 void add_history(char *);
270 p = readline("ftp> ");
272 p = simple_readline("ftp> ");
277 strlcpy(line, p, sizeof(line));
282 if (fgets(line, sizeof line, stdin) == NULL)
285 /* XXX will break on long lines */
289 if (line[--l] == '\n') {
293 } else if (l == sizeof(line) - 2) {
294 printf("sorry, input line too long\n");
295 while ((l = getchar()) != '\n' && l != EOF)
298 } /* else it was a line without a newline */
303 c = getcmd(margv[0]);
304 if (c == (struct cmd *)-1) {
305 printf("?Ambiguous command\n");
309 printf("?Invalid command\n");
312 if (c->c_conn && !connected) {
313 printf("Not connected.\n");
316 (*c->c_handler)(margc, margv);
317 if (bell && c->c_bell)
319 if (c->c_handler != help)
322 signal(SIGINT, intr);
323 signal(SIGPIPE, lostpeer);
330 struct cmd *c, *found;
331 int nmatches, longest;
336 for (c = cmdtab; (p = c->c_name); c++) {
337 for (q = name; *q == *p++; q++)
338 if (*q == 0) /* exact match? */
340 if (!*q) { /* the name was a prefix */
341 if (q - name > longest) {
345 } else if (q - name == longest)
350 return ((struct cmd *)-1);
355 * Slice a string up into argc/argv.
366 stringbase = line; /* scan from first of buffer */
367 argbase = argbuf; /* store from first of buffer */
369 for (margc = 0; ; margc++) {
370 /* Expand array if necessary */
371 if (margc == margvlen) {
374 margv = (margvlen == 0)
375 ? (char **)malloc(20 * sizeof(char *))
376 : (char **)realloc(margv,
377 (margvlen + 20)*sizeof(char *));
379 errx(1, "cannot realloc argv array");
380 for(i = margvlen; i < margvlen + 20; ++i)
383 argp = margv + margc;
386 if ((*argp++ = slurpstring()) == NULL)
393 * Parse string into argbuf;
394 * implemented with FSM to
395 * handle quoting and strings
401 char *sb = stringbase;
403 char *tmp = argbase; /* will return this if token found */
405 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
406 switch (slrflag) { /* and $ as token for macro invoke */
410 return ((*sb == '!') ? "!" : "$");
452 goto OUT; /* end of token */
455 sb++; goto S2; /* slurp next character */
458 sb++; goto S3; /* slurp quoted string */
461 *ap++ = *sb++; /* add character to token */
496 argbase = ap; /* update storage pointer */
497 stringbase = sb; /* update scan pointer */
515 #define HELPINDENT ((int) sizeof ("directory"))
519 * Call each command handler with argc == 0 and argv[0] == name.
522 help(int argc, char **argv)
528 int columns, width = 0, lines;
530 printf("Commands may be abbreviated. Commands are:\n\n");
531 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
532 int len = strlen(c->c_name);
537 width = (width + 8) &~ 7;
538 columns = 80 / width;
541 lines = (NCMDS + columns - 1) / columns;
542 for (i = 0; i < lines; i++) {
543 for (j = 0; j < columns; j++) {
544 c = cmdtab + j * lines + i;
545 if (c->c_name && (!proxy || c->c_proxy)) {
546 printf("%s", c->c_name);
548 else if (c->c_name) {
549 for (k=0; k < strlen(c->c_name); k++) {
553 if (c + lines >= &cmdtab[NCMDS]) {
557 w = strlen(c->c_name);
570 if (c == (struct cmd *)-1)
571 printf("?Ambiguous help command %s\n", arg);
572 else if (c == (struct cmd *)0)
573 printf("?Invalid help command %s\n", arg);
575 printf("%-*s\t%s\n", HELPINDENT,
576 c->c_name, c->c_help);