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