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 are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)main.c 5.14 (Berkeley) 05/17/89"; 26 #endif /* not lint */ 27 28 /* 29 * FTP User Program -- Command Interface. 30 */ 31 #include "ftp_var.h" 32 #include <sys/socket.h> 33 #include <sys/ioctl.h> 34 #include <sys/types.h> 35 36 #include <arpa/ftp.h> 37 38 #include <signal.h> 39 #include <stdio.h> 40 #include <errno.h> 41 #include <ctype.h> 42 #include <netdb.h> 43 #include <pwd.h> 44 45 46 uid_t getuid(); 47 int intr(); 48 int lostpeer(); 49 extern char *home; 50 char *getlogin(); 51 52 main(argc, argv) 53 char *argv[]; 54 { 55 register char *cp; 56 int top; 57 struct passwd *pw = NULL; 58 char homedir[MAXPATHLEN]; 59 60 sp = getservbyname("ftp", "tcp"); 61 if (sp == 0) { 62 fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); 63 exit(1); 64 } 65 doglob = 1; 66 interactive = 1; 67 autologin = 1; 68 argc--, argv++; 69 while (argc > 0 && **argv == '-') { 70 for (cp = *argv + 1; *cp; cp++) 71 switch (*cp) { 72 73 case 'd': 74 options |= SO_DEBUG; 75 debug++; 76 break; 77 78 case 'v': 79 verbose++; 80 break; 81 82 case 't': 83 trace++; 84 break; 85 86 case 'i': 87 interactive = 0; 88 break; 89 90 case 'n': 91 autologin = 0; 92 break; 93 94 case 'g': 95 doglob = 0; 96 break; 97 98 default: 99 fprintf(stdout, 100 "ftp: %c: unknown option\n", *cp); 101 exit(1); 102 } 103 argc--, argv++; 104 } 105 fromatty = isatty(fileno(stdin)); 106 if (fromatty) 107 verbose++; 108 cpend = 0; /* no pending replies */ 109 proxy = 0; /* proxy not active */ 110 crflag = 1; /* strip c.r. on ascii gets */ 111 /* 112 * Set up the home directory in case we're globbing. 113 */ 114 cp = getlogin(); 115 if (cp != NULL) { 116 pw = getpwnam(cp); 117 } 118 if (pw == NULL) 119 pw = getpwuid(getuid()); 120 if (pw != NULL) { 121 home = homedir; 122 (void) strcpy(home, pw->pw_dir); 123 } 124 if (argc > 0) { 125 if (setjmp(toplevel)) 126 exit(0); 127 (void) signal(SIGINT, intr); 128 (void) signal(SIGPIPE, lostpeer); 129 setpeer(argc + 1, argv - 1); 130 } 131 top = setjmp(toplevel) == 0; 132 if (top) { 133 (void) signal(SIGINT, intr); 134 (void) signal(SIGPIPE, lostpeer); 135 } 136 for (;;) { 137 cmdscanner(top); 138 top = 1; 139 } 140 } 141 142 intr() 143 { 144 145 longjmp(toplevel, 1); 146 } 147 148 lostpeer() 149 { 150 extern FILE *cout; 151 extern int data; 152 153 if (connected) { 154 if (cout != NULL) { 155 (void) shutdown(fileno(cout), 1+1); 156 (void) fclose(cout); 157 cout = NULL; 158 } 159 if (data >= 0) { 160 (void) shutdown(data, 1+1); 161 (void) close(data); 162 data = -1; 163 } 164 connected = 0; 165 } 166 pswitch(1); 167 if (connected) { 168 if (cout != NULL) { 169 (void) shutdown(fileno(cout), 1+1); 170 (void) fclose(cout); 171 cout = NULL; 172 } 173 connected = 0; 174 } 175 proxflag = 0; 176 pswitch(0); 177 } 178 179 /*char * 180 tail(filename) 181 char *filename; 182 { 183 register char *s; 184 185 while (*filename) { 186 s = rindex(filename, '/'); 187 if (s == NULL) 188 break; 189 if (s[1]) 190 return (s + 1); 191 *s = '\0'; 192 } 193 return (filename); 194 } 195 */ 196 /* 197 * Command parser. 198 */ 199 cmdscanner(top) 200 int top; 201 { 202 register struct cmd *c; 203 struct cmd *getcmd(); 204 extern int help(); 205 206 if (!top) 207 (void) putchar('\n'); 208 for (;;) { 209 if (fromatty) { 210 printf("ftp> "); 211 (void) fflush(stdout); 212 } 213 if (gets(line) == 0) { 214 if (feof(stdin) || ferror(stdin)) 215 quit(); 216 break; 217 } 218 if (line[0] == 0) 219 break; 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 488 /* 489 * Call routine with argc, argv set from args (terminated by 0). 490 */ 491 /*VARARGS1*/ 492 call(routine, args) 493 int (*routine)(); 494 int args; 495 { 496 register int *argp; 497 register int argc; 498 499 for (argc = 0, argp = &args; *argp++ != 0; argc++) 500 ; 501 (*routine)(argc, &args); 502 } 503