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.6 (Berkeley) 03/07/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 #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 struct cmd cmdtab[]; 202 extern int help(); 203 204 if (!top) 205 (void) putchar('\n'); 206 for (;;) { 207 if (fromatty) { 208 printf("ftp> "); 209 (void) fflush(stdout); 210 } 211 if (gets(line) == 0) { 212 if (feof(stdin)) 213 quit(); 214 break; 215 } 216 if (line[0] == 0) 217 break; 218 makeargv(); 219 if (margc == 0) { 220 continue; 221 } 222 c = getcmd(margv[0]); 223 if (c == (struct cmd *)-1) { 224 printf("?Ambiguous command\n"); 225 continue; 226 } 227 if (c == 0) { 228 printf("?Invalid command\n"); 229 continue; 230 } 231 if (c->c_conn && !connected) { 232 printf ("Not connected.\n"); 233 continue; 234 } 235 (*c->c_handler)(margc, margv); 236 if (bell && c->c_bell) 237 (void) putchar(CTRL(g)); 238 if (c->c_handler != help) 239 break; 240 } 241 (void) signal(SIGINT, intr); 242 (void) signal(SIGPIPE, lostpeer); 243 } 244 245 struct cmd * 246 getcmd(name) 247 register char *name; 248 { 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 register struct cmd *c; 428 429 if (argc == 1) { 430 register int i, j, w, k; 431 int columns, width = 0, lines; 432 extern int NCMDS; 433 434 printf("Commands may be abbreviated. Commands are:\n\n"); 435 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 436 int len = strlen(c->c_name); 437 438 if (len > width) 439 width = len; 440 } 441 width = (width + 8) &~ 7; 442 columns = 80 / width; 443 if (columns == 0) 444 columns = 1; 445 lines = (NCMDS + columns - 1) / columns; 446 for (i = 0; i < lines; i++) { 447 for (j = 0; j < columns; j++) { 448 c = cmdtab + j * lines + i; 449 if (c->c_name && (!proxy || c->c_proxy)) { 450 printf("%s", c->c_name); 451 } 452 else if (c->c_name) { 453 for (k=0; k < strlen(c->c_name); k++) { 454 (void) putchar(' '); 455 } 456 } 457 if (c + lines >= &cmdtab[NCMDS]) { 458 printf("\n"); 459 break; 460 } 461 w = strlen(c->c_name); 462 while (w < width) { 463 w = (w + 8) &~ 7; 464 (void) putchar('\t'); 465 } 466 } 467 } 468 return; 469 } 470 while (--argc > 0) { 471 register char *arg; 472 arg = *++argv; 473 c = getcmd(arg); 474 if (c == (struct cmd *)-1) 475 printf("?Ambiguous help command %s\n", arg); 476 else if (c == (struct cmd *)0) 477 printf("?Invalid help command %s\n", arg); 478 else 479 printf("%-*s\t%s\n", HELPINDENT, 480 c->c_name, c->c_help); 481 } 482 } 483 484 /* 485 * Call routine with argc, argv set from args (terminated by 0). 486 */ 487 /*VARARGS1*/ 488 call(routine, args) 489 int (*routine)(); 490 int args; 491 { 492 register int *argp; 493 register int argc; 494 495 for (argc = 0, argp = &args; *argp++ != 0; argc++) 496 ; 497 (*routine)(argc, &args); 498 } 499