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