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