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