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.10 1995/09/15 00:32:33 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 longest = 0; 292 nmatches = 0; 293 found = 0; 294 for (c = cmdtab; p = c->c_name; c++) { 295 for (q = name; *q == *p++; q++) 296 if (*q == 0) /* exact match? */ 297 return (c); 298 if (!*q) { /* the name was a prefix */ 299 if (q - name > longest) { 300 longest = q - name; 301 nmatches = 1; 302 found = c; 303 } else if (q - name == longest) 304 nmatches++; 305 } 306 } 307 if (nmatches > 1) 308 return ((struct cmd *)-1); 309 return (found); 310 } 311 312 /* 313 * Slice a string up into argc/argv. 314 */ 315 316 int slrflag; 317 318 void 319 makeargv() 320 { 321 char **argp; 322 323 argp = margv; 324 stringbase = line; /* scan from first of buffer */ 325 argbase = argbuf; /* store from first of buffer */ 326 slrflag = 0; 327 for (margc = 0; ; margc++) { 328 /* Expand array if necessary */ 329 if (margc == margvlen) { 330 margv = (margvlen == 0) 331 ? (char **)malloc(20 * sizeof(char *)) 332 : (char **)realloc(margv, 333 (margvlen + 20)*sizeof(char *)); 334 if (margv == NULL) 335 errx(1, "cannot realloc argv array"); 336 margvlen += 20; 337 argp = margv + margc; 338 } 339 340 if ((*argp++ = slurpstring()) == NULL) 341 break; 342 } 343 344 } 345 346 /* 347 * Parse string into argbuf; 348 * implemented with FSM to 349 * handle quoting and strings 350 */ 351 char * 352 slurpstring() 353 { 354 int got_one = 0; 355 char *sb = stringbase; 356 char *ap = argbase; 357 char *tmp = argbase; /* will return this if token found */ 358 359 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ 360 switch (slrflag) { /* and $ as token for macro invoke */ 361 case 0: 362 slrflag++; 363 stringbase++; 364 return ((*sb == '!') ? "!" : "$"); 365 /* NOTREACHED */ 366 case 1: 367 slrflag++; 368 altarg = stringbase; 369 break; 370 default: 371 break; 372 } 373 } 374 375 S0: 376 switch (*sb) { 377 378 case '\0': 379 goto OUT; 380 381 case ' ': 382 case '\t': 383 sb++; goto S0; 384 385 default: 386 switch (slrflag) { 387 case 0: 388 slrflag++; 389 break; 390 case 1: 391 slrflag++; 392 altarg = sb; 393 break; 394 default: 395 break; 396 } 397 goto S1; 398 } 399 400 S1: 401 switch (*sb) { 402 403 case ' ': 404 case '\t': 405 case '\0': 406 goto OUT; /* end of token */ 407 408 case '\\': 409 sb++; goto S2; /* slurp next character */ 410 411 case '"': 412 sb++; goto S3; /* slurp quoted string */ 413 414 default: 415 *ap++ = *sb++; /* add character to token */ 416 got_one = 1; 417 goto S1; 418 } 419 420 S2: 421 switch (*sb) { 422 423 case '\0': 424 goto OUT; 425 426 default: 427 *ap++ = *sb++; 428 got_one = 1; 429 goto S1; 430 } 431 432 S3: 433 switch (*sb) { 434 435 case '\0': 436 goto OUT; 437 438 case '"': 439 sb++; goto S1; 440 441 default: 442 *ap++ = *sb++; 443 got_one = 1; 444 goto S3; 445 } 446 447 OUT: 448 if (got_one) 449 *ap++ = '\0'; 450 argbase = ap; /* update storage pointer */ 451 stringbase = sb; /* update scan pointer */ 452 if (got_one) { 453 return (tmp); 454 } 455 switch (slrflag) { 456 case 0: 457 slrflag++; 458 break; 459 case 1: 460 slrflag++; 461 altarg = (char *) 0; 462 break; 463 default: 464 break; 465 } 466 return ((char *)0); 467 } 468 469 #define HELPINDENT ((int) sizeof ("directory")) 470 471 /* 472 * Help command. 473 * Call each command handler with argc == 0 and argv[0] == name. 474 */ 475 void 476 help(argc, argv) 477 int argc; 478 char *argv[]; 479 { 480 struct cmd *c; 481 482 if (argc == 1) { 483 int i, j, w, k; 484 int columns, width = 0, lines; 485 486 printf("Commands may be abbreviated. Commands are:\n\n"); 487 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 488 int len = strlen(c->c_name); 489 490 if (len > width) 491 width = len; 492 } 493 width = (width + 8) &~ 7; 494 columns = 80 / width; 495 if (columns == 0) 496 columns = 1; 497 lines = (NCMDS + columns - 1) / columns; 498 for (i = 0; i < lines; i++) { 499 for (j = 0; j < columns; j++) { 500 c = cmdtab + j * lines + i; 501 if (c->c_name && (!proxy || c->c_proxy)) { 502 printf("%s", c->c_name); 503 } 504 else if (c->c_name) { 505 for (k=0; k < strlen(c->c_name); k++) { 506 (void) putchar(' '); 507 } 508 } 509 if (c + lines >= &cmdtab[NCMDS]) { 510 printf("\n"); 511 break; 512 } 513 w = strlen(c->c_name); 514 while (w < width) { 515 w = (w + 8) &~ 7; 516 (void) putchar('\t'); 517 } 518 } 519 } 520 return; 521 } 522 while (--argc > 0) { 523 char *arg; 524 arg = *++argv; 525 c = getcmd(arg); 526 if (c == (struct cmd *)-1) 527 printf("?Ambiguous help command %s\n", arg); 528 else if (c == (struct cmd *)0) 529 printf("?Invalid help command %s\n", arg); 530 else 531 printf("%-*s\t%s\n", HELPINDENT, 532 c->c_name, c->c_help); 533 } 534 } 535