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