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