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