1 /* 2 * Copyright (c) 1985, 1989, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 20 * 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 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char copyright[] = 36 "@(#) Copyright (c) 1985, 1989, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 4/3/94";*/ 42 static char *rcsid = "$Id: main.c,v 1.6 1994/08/31 21:32:33 mycroft Exp $"; 43 #endif /* not lint */ 44 45 /* 46 * FTP User Program -- Command Interface. 47 */ 48 /*#include <sys/ioctl.h>*/ 49 #include <sys/types.h> 50 #include <sys/socket.h> 51 52 #include <arpa/ftp.h> 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <netdb.h> 57 #include <pwd.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <unistd.h> 62 63 #include "ftp_var.h" 64 65 int 66 main(argc, argv) 67 int argc; 68 char *argv[]; 69 { 70 int ch, top; 71 struct passwd *pw = NULL; 72 char *cp, homedir[MAXPATHLEN]; 73 74 sp = getservbyname("ftp", "tcp"); 75 if (sp == 0) 76 errx(1, "ftp/tcp: unknown service"); 77 doglob = 1; 78 interactive = 1; 79 autologin = 1; 80 81 while ((ch = getopt(argc, argv, "dgintv")) != -1) { 82 switch (ch) { 83 case 'd': 84 options |= SO_DEBUG; 85 debug++; 86 break; 87 88 case 'g': 89 doglob = 0; 90 break; 91 92 case 'i': 93 interactive = 0; 94 break; 95 96 case 'n': 97 autologin = 0; 98 break; 99 100 case 't': 101 trace++; 102 break; 103 104 case 'v': 105 verbose++; 106 break; 107 108 default: 109 (void)fprintf(stderr, 110 "usage: ftp [-dgintv] [host [port]]\n"); 111 exit(1); 112 } 113 } 114 argc -= optind; 115 argv += optind; 116 117 fromatty = isatty(fileno(stdin)); 118 if (fromatty) 119 verbose++; 120 cpend = 0; /* no pending replies */ 121 proxy = 0; /* proxy not active */ 122 passivemode = 0; /* passive mode not active */ 123 crflag = 1; /* strip c.r. on ascii gets */ 124 sendport = -1; /* not using ports */ 125 /* 126 * Set up the home directory in case we're globbing. 127 */ 128 cp = getlogin(); 129 if (cp != NULL) { 130 pw = getpwnam(cp); 131 } 132 if (pw == NULL) 133 pw = getpwuid(getuid()); 134 if (pw != NULL) { 135 home = homedir; 136 (void) strcpy(home, pw->pw_dir); 137 } 138 if (argc > 0) { 139 char *xargv[5]; 140 extern char *__progname; 141 142 if (setjmp(toplevel)) 143 exit(0); 144 (void) signal(SIGINT, intr); 145 (void) signal(SIGPIPE, lostpeer); 146 xargv[0] = __progname; 147 xargv[1] = argv[0]; 148 xargv[2] = argv[1]; 149 xargv[3] = argv[2]; 150 xargv[4] = NULL; 151 setpeer(argc+1, xargv); 152 } 153 top = setjmp(toplevel) == 0; 154 if (top) { 155 (void) signal(SIGINT, intr); 156 (void) signal(SIGPIPE, lostpeer); 157 } 158 for (;;) { 159 cmdscanner(top); 160 top = 1; 161 } 162 } 163 164 void 165 intr() 166 { 167 168 longjmp(toplevel, 1); 169 } 170 171 void 172 lostpeer() 173 { 174 175 if (connected) { 176 if (cout != NULL) { 177 (void) shutdown(fileno(cout), 1+1); 178 (void) fclose(cout); 179 cout = NULL; 180 } 181 if (data >= 0) { 182 (void) shutdown(data, 1+1); 183 (void) close(data); 184 data = -1; 185 } 186 connected = 0; 187 } 188 pswitch(1); 189 if (connected) { 190 if (cout != NULL) { 191 (void) shutdown(fileno(cout), 1+1); 192 (void) fclose(cout); 193 cout = NULL; 194 } 195 connected = 0; 196 } 197 proxflag = 0; 198 pswitch(0); 199 } 200 201 /* 202 char * 203 tail(filename) 204 char *filename; 205 { 206 char *s; 207 208 while (*filename) { 209 s = strrchr(filename, '/'); 210 if (s == NULL) 211 break; 212 if (s[1]) 213 return (s + 1); 214 *s = '\0'; 215 } 216 return (filename); 217 } 218 */ 219 220 /* 221 * Command parser. 222 */ 223 void 224 cmdscanner(top) 225 int top; 226 { 227 struct cmd *c; 228 int l; 229 230 if (!top) 231 (void) putchar('\n'); 232 for (;;) { 233 if (fromatty) { 234 printf("ftp> "); 235 (void) fflush(stdout); 236 } 237 if (fgets(line, sizeof line, stdin) == NULL) 238 quit(0, 0); 239 l = strlen(line); 240 if (l == 0) 241 break; 242 if (line[--l] == '\n') { 243 if (l == 0) 244 break; 245 line[l] = '\0'; 246 } else if (l == sizeof(line) - 2) { 247 printf("sorry, input line too long\n"); 248 while ((l = getchar()) != '\n' && l != EOF) 249 /* void */; 250 break; 251 } /* else it was a line without a newline */ 252 makeargv(); 253 if (margc == 0) { 254 continue; 255 } 256 c = getcmd(margv[0]); 257 if (c == (struct cmd *)-1) { 258 printf("?Ambiguous command\n"); 259 continue; 260 } 261 if (c == 0) { 262 printf("?Invalid command\n"); 263 continue; 264 } 265 if (c->c_conn && !connected) { 266 printf("Not connected.\n"); 267 continue; 268 } 269 (*c->c_handler)(margc, margv); 270 if (bell && c->c_bell) 271 (void) putchar('\007'); 272 if (c->c_handler != help) 273 break; 274 } 275 (void) signal(SIGINT, intr); 276 (void) signal(SIGPIPE, lostpeer); 277 } 278 279 struct cmd * 280 getcmd(name) 281 char *name; 282 { 283 char *p, *q; 284 struct cmd *c, *found; 285 int nmatches, longest; 286 287 longest = 0; 288 nmatches = 0; 289 found = 0; 290 for (c = cmdtab; p = c->c_name; c++) { 291 for (q = name; *q == *p++; q++) 292 if (*q == 0) /* exact match? */ 293 return (c); 294 if (!*q) { /* the name was a prefix */ 295 if (q - name > longest) { 296 longest = q - name; 297 nmatches = 1; 298 found = c; 299 } else if (q - name == longest) 300 nmatches++; 301 } 302 } 303 if (nmatches > 1) 304 return ((struct cmd *)-1); 305 return (found); 306 } 307 308 /* 309 * Slice a string up into argc/argv. 310 */ 311 312 int slrflag; 313 314 void 315 makeargv() 316 { 317 char **argp; 318 319 margc = 0; 320 argp = margv; 321 stringbase = line; /* scan from first of buffer */ 322 argbase = argbuf; /* store from first of buffer */ 323 slrflag = 0; 324 while (*argp++ = slurpstring()) 325 margc++; 326 } 327 328 /* 329 * Parse string into argbuf; 330 * implemented with FSM to 331 * handle quoting and strings 332 */ 333 char * 334 slurpstring() 335 { 336 int got_one = 0; 337 char *sb = stringbase; 338 char *ap = argbase; 339 char *tmp = argbase; /* will return this if token found */ 340 341 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ 342 switch (slrflag) { /* and $ as token for macro invoke */ 343 case 0: 344 slrflag++; 345 stringbase++; 346 return ((*sb == '!') ? "!" : "$"); 347 /* NOTREACHED */ 348 case 1: 349 slrflag++; 350 altarg = stringbase; 351 break; 352 default: 353 break; 354 } 355 } 356 357 S0: 358 switch (*sb) { 359 360 case '\0': 361 goto OUT; 362 363 case ' ': 364 case '\t': 365 sb++; goto S0; 366 367 default: 368 switch (slrflag) { 369 case 0: 370 slrflag++; 371 break; 372 case 1: 373 slrflag++; 374 altarg = sb; 375 break; 376 default: 377 break; 378 } 379 goto S1; 380 } 381 382 S1: 383 switch (*sb) { 384 385 case ' ': 386 case '\t': 387 case '\0': 388 goto OUT; /* end of token */ 389 390 case '\\': 391 sb++; goto S2; /* slurp next character */ 392 393 case '"': 394 sb++; goto S3; /* slurp quoted string */ 395 396 default: 397 *ap++ = *sb++; /* add character to token */ 398 got_one = 1; 399 goto S1; 400 } 401 402 S2: 403 switch (*sb) { 404 405 case '\0': 406 goto OUT; 407 408 default: 409 *ap++ = *sb++; 410 got_one = 1; 411 goto S1; 412 } 413 414 S3: 415 switch (*sb) { 416 417 case '\0': 418 goto OUT; 419 420 case '"': 421 sb++; goto S1; 422 423 default: 424 *ap++ = *sb++; 425 got_one = 1; 426 goto S3; 427 } 428 429 OUT: 430 if (got_one) 431 *ap++ = '\0'; 432 argbase = ap; /* update storage pointer */ 433 stringbase = sb; /* update scan pointer */ 434 if (got_one) { 435 return (tmp); 436 } 437 switch (slrflag) { 438 case 0: 439 slrflag++; 440 break; 441 case 1: 442 slrflag++; 443 altarg = (char *) 0; 444 break; 445 default: 446 break; 447 } 448 return ((char *)0); 449 } 450 451 #define HELPINDENT ((int) sizeof ("directory")) 452 453 /* 454 * Help command. 455 * Call each command handler with argc == 0 and argv[0] == name. 456 */ 457 void 458 help(argc, argv) 459 int argc; 460 char *argv[]; 461 { 462 struct cmd *c; 463 464 if (argc == 1) { 465 int i, j, w, k; 466 int columns, width = 0, lines; 467 468 printf("Commands may be abbreviated. Commands are:\n\n"); 469 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 470 int len = strlen(c->c_name); 471 472 if (len > width) 473 width = len; 474 } 475 width = (width + 8) &~ 7; 476 columns = 80 / width; 477 if (columns == 0) 478 columns = 1; 479 lines = (NCMDS + columns - 1) / columns; 480 for (i = 0; i < lines; i++) { 481 for (j = 0; j < columns; j++) { 482 c = cmdtab + j * lines + i; 483 if (c->c_name && (!proxy || c->c_proxy)) { 484 printf("%s", c->c_name); 485 } 486 else if (c->c_name) { 487 for (k=0; k < strlen(c->c_name); k++) { 488 (void) putchar(' '); 489 } 490 } 491 if (c + lines >= &cmdtab[NCMDS]) { 492 printf("\n"); 493 break; 494 } 495 w = strlen(c->c_name); 496 while (w < width) { 497 w = (w + 8) &~ 7; 498 (void) putchar('\t'); 499 } 500 } 501 } 502 return; 503 } 504 while (--argc > 0) { 505 char *arg; 506 arg = *++argv; 507 c = getcmd(arg); 508 if (c == (struct cmd *)-1) 509 printf("?Ambiguous help command %s\n", arg); 510 else if (c == (struct cmd *)0) 511 printf("?Invalid help command %s\n", arg); 512 else 513 printf("%-*s\t%s\n", HELPINDENT, 514 c->c_name, c->c_help); 515 } 516 } 517