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