1 /* 2 * Copyright (c) 1983 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) 1983 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.2 (Berkeley) 01/10/86"; 15 #endif not lint 16 17 /* 18 * FTP User Program -- Command Interface. 19 */ 20 #include <sys/param.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 #include "ftp_var.h" 34 35 int intr(); 36 int lostpeer(); 37 extern char *home; 38 39 main(argc, argv) 40 char *argv[]; 41 { 42 register char *cp; 43 int top; 44 struct passwd *pw; 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 /* 104 * Set up the home directory in case we're globbing. 105 */ 106 pw = getpwnam(getlogin()); 107 if (pw == NULL) 108 pw = getpwuid(getuid()); 109 if (pw != NULL) { 110 home = homedir; 111 strcpy(home, pw->pw_dir); 112 } 113 if (argc > 0) { 114 if (setjmp(toplevel)) 115 exit(0); 116 signal(SIGINT, intr); 117 signal(SIGPIPE, lostpeer); 118 setpeer(argc + 1, argv - 1); 119 } 120 top = setjmp(toplevel) == 0; 121 if (top) { 122 signal(SIGINT, intr); 123 signal(SIGPIPE, lostpeer); 124 } 125 for (;;) { 126 cmdscanner(top); 127 top = 1; 128 } 129 } 130 131 intr() 132 { 133 134 longjmp(toplevel, 1); 135 } 136 137 lostpeer() 138 { 139 extern FILE *cout; 140 extern int data; 141 142 if (connected) { 143 if (cout != NULL) { 144 shutdown(fileno(cout), 1+1); 145 fclose(cout); 146 cout = NULL; 147 } 148 if (data >= 0) { 149 shutdown(data, 1+1); 150 (void) close(data); 151 data = -1; 152 } 153 connected = 0; 154 } 155 longjmp(toplevel, 1); 156 } 157 158 char * 159 tail(filename) 160 char *filename; 161 { 162 register char *s; 163 164 while (*filename) { 165 s = rindex(filename, '/'); 166 if (s == NULL) 167 break; 168 if (s[1]) 169 return (s + 1); 170 *s = '\0'; 171 } 172 return (filename); 173 } 174 175 /* 176 * Command parser. 177 */ 178 cmdscanner(top) 179 int top; 180 { 181 register struct cmd *c; 182 struct cmd *getcmd(); 183 extern struct cmd cmdtab[]; 184 extern int help(); 185 186 if (!top) 187 putchar('\n'); 188 for (;;) { 189 if (fromatty) { 190 printf("ftp> "); 191 fflush(stdout); 192 } 193 if (gets(line) == 0) { 194 if (feof(stdin)) 195 quit(); 196 break; 197 } 198 if (line[0] == 0) 199 break; 200 makeargv(); 201 c = getcmd(margv[0]); 202 if (c == (struct cmd *)-1) { 203 printf("?Ambiguous command\n"); 204 continue; 205 } 206 if (c == 0) { 207 printf("?Invalid command\n"); 208 continue; 209 } 210 if (c->c_conn && !connected) { 211 printf ("Not connected.\n"); 212 continue; 213 } 214 (*c->c_handler)(margc, margv); 215 if (bell && c->c_bell) 216 putchar(CTRL(g)); 217 if (c->c_handler != help) 218 break; 219 } 220 longjmp(toplevel, 0); 221 } 222 223 struct cmd * 224 getcmd(name) 225 register char *name; 226 { 227 register char *p, *q; 228 register struct cmd *c, *found; 229 register int nmatches, longest; 230 231 longest = 0; 232 nmatches = 0; 233 found = 0; 234 for (c = cmdtab; p = c->c_name; c++) { 235 for (q = name; *q == *p++; q++) 236 if (*q == 0) /* exact match? */ 237 return (c); 238 if (!*q) { /* the name was a prefix */ 239 if (q - name > longest) { 240 longest = q - name; 241 nmatches = 1; 242 found = c; 243 } else if (q - name == longest) 244 nmatches++; 245 } 246 } 247 if (nmatches > 1) 248 return ((struct cmd *)-1); 249 return (found); 250 } 251 252 /* 253 * Slice a string up into argc/argv. 254 */ 255 makeargv() 256 { 257 char **argp; 258 char *slurpstring(); 259 260 margc = 0; 261 argp = margv; 262 stringbase = line; /* scan from first of buffer */ 263 argbase = argbuf; /* store from first of buffer */ 264 while (*argp++ = slurpstring()) 265 margc++; 266 } 267 268 /* 269 * Parse string into argbuf; 270 * implemented with FSM to 271 * handle quoting and strings 272 */ 273 char * 274 slurpstring() 275 { 276 int got_one = 0; 277 register char *sb = stringbase; 278 register char *ap = argbase; 279 char *tmp = argbase; /* will return this if token found */ 280 281 if (*sb == '!') { /* recognize ! as a token for shell */ 282 stringbase++; 283 return ("!"); 284 } 285 S0: 286 switch (*sb) { 287 288 case '\0': 289 goto OUT; 290 291 case ' ': 292 case '\t': 293 sb++; goto S0; 294 295 default: 296 goto S1; 297 } 298 299 S1: 300 switch (*sb) { 301 302 case ' ': 303 case '\t': 304 case '\0': 305 goto OUT; /* end of token */ 306 307 case '\\': 308 sb++; goto S2; /* slurp next character */ 309 310 case '"': 311 sb++; goto S3; /* slurp quoted string */ 312 313 default: 314 *ap++ = *sb++; /* add character to token */ 315 got_one = 1; 316 goto S1; 317 } 318 319 S2: 320 switch (*sb) { 321 322 case '\0': 323 goto OUT; 324 325 default: 326 *ap++ = *sb++; 327 got_one = 1; 328 goto S1; 329 } 330 331 S3: 332 switch (*sb) { 333 334 case '\0': 335 goto OUT; 336 337 case '"': 338 sb++; goto S1; 339 340 default: 341 *ap++ = *sb++; 342 got_one = 1; 343 goto S3; 344 } 345 346 OUT: 347 if (got_one) 348 *ap++ = '\0'; 349 argbase = ap; /* update storage pointer */ 350 stringbase = sb; /* update scan pointer */ 351 if (got_one) 352 return(tmp); 353 return((char *)0); 354 } 355 356 #define HELPINDENT (sizeof ("directory")) 357 358 /* 359 * Help command. 360 * Call each command handler with argc == 0 and argv[0] == name. 361 */ 362 help(argc, argv) 363 int argc; 364 char *argv[]; 365 { 366 register struct cmd *c; 367 368 if (argc == 1) { 369 register int i, j, w; 370 int columns, width = 0, lines; 371 extern int NCMDS; 372 373 printf("Commands may be abbreviated. Commands are:\n\n"); 374 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 375 int len = strlen(c->c_name); 376 377 if (len > width) 378 width = len; 379 } 380 width = (width + 8) &~ 7; 381 columns = 80 / width; 382 if (columns == 0) 383 columns = 1; 384 lines = (NCMDS + columns - 1) / columns; 385 for (i = 0; i < lines; i++) { 386 for (j = 0; j < columns; j++) { 387 c = cmdtab + j * lines + i; 388 printf("%s", c->c_name); 389 if (c + lines >= &cmdtab[NCMDS]) { 390 printf("\n"); 391 break; 392 } 393 w = strlen(c->c_name); 394 while (w < width) { 395 w = (w + 8) &~ 7; 396 putchar('\t'); 397 } 398 } 399 } 400 return; 401 } 402 while (--argc > 0) { 403 register char *arg; 404 arg = *++argv; 405 c = getcmd(arg); 406 if (c == (struct cmd *)-1) 407 printf("?Ambiguous help command %s\n", arg); 408 else if (c == (struct cmd *)0) 409 printf("?Invalid help command %s\n", arg); 410 else 411 printf("%-*s\t%s\n", HELPINDENT, 412 c->c_name, c->c_help); 413 } 414 } 415 416 /* 417 * Call routine with argc, argv set from args (terminated by 0). 418 */ 419 /* VARARGS2 */ 420 call(routine, args) 421 int (*routine)(); 422 int args; 423 { 424 register int *argp; 425 register int argc; 426 427 for (argc = 0, argp = &args; *argp++ != 0; argc++) 428 ; 429 (*routine)(argc, &args); 430 } 431