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