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