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