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.16 (Berkeley) 06/01/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 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 (gets(line) == 0) { 206 if (feof(stdin) || ferror(stdin)) 207 quit(); 208 break; 209 } 210 if (line[0] == 0) 211 break; 212 makeargv(); 213 if (margc == 0) { 214 continue; 215 } 216 c = getcmd(margv[0]); 217 if (c == (struct cmd *)-1) { 218 printf("?Ambiguous command\n"); 219 continue; 220 } 221 if (c == 0) { 222 printf("?Invalid command\n"); 223 continue; 224 } 225 if (c->c_conn && !connected) { 226 printf ("Not connected.\n"); 227 continue; 228 } 229 (*c->c_handler)(margc, margv); 230 if (bell && c->c_bell) 231 (void) putchar('\007'); 232 if (c->c_handler != help) 233 break; 234 } 235 (void) signal(SIGINT, intr); 236 (void) signal(SIGPIPE, lostpeer); 237 } 238 239 struct cmd * 240 getcmd(name) 241 register char *name; 242 { 243 extern struct cmd cmdtab[]; 244 register char *p, *q; 245 register struct cmd *c, *found; 246 register int nmatches, longest; 247 248 longest = 0; 249 nmatches = 0; 250 found = 0; 251 for (c = cmdtab; p = c->c_name; c++) { 252 for (q = name; *q == *p++; q++) 253 if (*q == 0) /* exact match? */ 254 return (c); 255 if (!*q) { /* the name was a prefix */ 256 if (q - name > longest) { 257 longest = q - name; 258 nmatches = 1; 259 found = c; 260 } else if (q - name == longest) 261 nmatches++; 262 } 263 } 264 if (nmatches > 1) 265 return ((struct cmd *)-1); 266 return (found); 267 } 268 269 /* 270 * Slice a string up into argc/argv. 271 */ 272 273 int slrflag; 274 275 makeargv() 276 { 277 char **argp; 278 char *slurpstring(); 279 280 margc = 0; 281 argp = margv; 282 stringbase = line; /* scan from first of buffer */ 283 argbase = argbuf; /* store from first of buffer */ 284 slrflag = 0; 285 while (*argp++ = slurpstring()) 286 margc++; 287 } 288 289 /* 290 * Parse string into argbuf; 291 * implemented with FSM to 292 * handle quoting and strings 293 */ 294 char * 295 slurpstring() 296 { 297 int got_one = 0; 298 register char *sb = stringbase; 299 register char *ap = argbase; 300 char *tmp = argbase; /* will return this if token found */ 301 302 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ 303 switch (slrflag) { /* and $ as token for macro invoke */ 304 case 0: 305 slrflag++; 306 stringbase++; 307 return ((*sb == '!') ? "!" : "$"); 308 /* NOTREACHED */ 309 case 1: 310 slrflag++; 311 altarg = stringbase; 312 break; 313 default: 314 break; 315 } 316 } 317 318 S0: 319 switch (*sb) { 320 321 case '\0': 322 goto OUT; 323 324 case ' ': 325 case '\t': 326 sb++; goto S0; 327 328 default: 329 switch (slrflag) { 330 case 0: 331 slrflag++; 332 break; 333 case 1: 334 slrflag++; 335 altarg = sb; 336 break; 337 default: 338 break; 339 } 340 goto S1; 341 } 342 343 S1: 344 switch (*sb) { 345 346 case ' ': 347 case '\t': 348 case '\0': 349 goto OUT; /* end of token */ 350 351 case '\\': 352 sb++; goto S2; /* slurp next character */ 353 354 case '"': 355 sb++; goto S3; /* slurp quoted string */ 356 357 default: 358 *ap++ = *sb++; /* add character to token */ 359 got_one = 1; 360 goto S1; 361 } 362 363 S2: 364 switch (*sb) { 365 366 case '\0': 367 goto OUT; 368 369 default: 370 *ap++ = *sb++; 371 got_one = 1; 372 goto S1; 373 } 374 375 S3: 376 switch (*sb) { 377 378 case '\0': 379 goto OUT; 380 381 case '"': 382 sb++; goto S1; 383 384 default: 385 *ap++ = *sb++; 386 got_one = 1; 387 goto S3; 388 } 389 390 OUT: 391 if (got_one) 392 *ap++ = '\0'; 393 argbase = ap; /* update storage pointer */ 394 stringbase = sb; /* update scan pointer */ 395 if (got_one) { 396 return(tmp); 397 } 398 switch (slrflag) { 399 case 0: 400 slrflag++; 401 break; 402 case 1: 403 slrflag++; 404 altarg = (char *) 0; 405 break; 406 default: 407 break; 408 } 409 return((char *)0); 410 } 411 412 #define HELPINDENT (sizeof ("directory")) 413 414 /* 415 * Help command. 416 * Call each command handler with argc == 0 and argv[0] == name. 417 */ 418 help(argc, argv) 419 int argc; 420 char *argv[]; 421 { 422 extern struct cmd cmdtab[]; 423 register struct cmd *c; 424 425 if (argc == 1) { 426 register int i, j, w, k; 427 int columns, width = 0, lines; 428 extern int NCMDS; 429 430 printf("Commands may be abbreviated. Commands are:\n\n"); 431 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 432 int len = strlen(c->c_name); 433 434 if (len > width) 435 width = len; 436 } 437 width = (width + 8) &~ 7; 438 columns = 80 / width; 439 if (columns == 0) 440 columns = 1; 441 lines = (NCMDS + columns - 1) / columns; 442 for (i = 0; i < lines; i++) { 443 for (j = 0; j < columns; j++) { 444 c = cmdtab + j * lines + i; 445 if (c->c_name && (!proxy || c->c_proxy)) { 446 printf("%s", c->c_name); 447 } 448 else if (c->c_name) { 449 for (k=0; k < strlen(c->c_name); k++) { 450 (void) putchar(' '); 451 } 452 } 453 if (c + lines >= &cmdtab[NCMDS]) { 454 printf("\n"); 455 break; 456 } 457 w = strlen(c->c_name); 458 while (w < width) { 459 w = (w + 8) &~ 7; 460 (void) putchar('\t'); 461 } 462 } 463 } 464 return; 465 } 466 while (--argc > 0) { 467 register char *arg; 468 arg = *++argv; 469 c = getcmd(arg); 470 if (c == (struct cmd *)-1) 471 printf("?Ambiguous help command %s\n", arg); 472 else if (c == (struct cmd *)0) 473 printf("?Invalid help command %s\n", arg); 474 else 475 printf("%-*s\t%s\n", HELPINDENT, 476 c->c_name, c->c_help); 477 } 478 } 479