1 #ifndef lint 2 static char sccsid[] = "@(#)main.c 4.10 (Berkeley) 07/19/84"; 3 #endif 4 5 /* 6 * FTP User Program -- Command Interface. 7 */ 8 #include <sys/param.h> 9 #include <sys/socket.h> 10 #include <sys/ioctl.h> 11 12 #include <arpa/ftp.h> 13 14 #include <signal.h> 15 #include <stdio.h> 16 #include <errno.h> 17 #include <ctype.h> 18 #include <netdb.h> 19 #include <pwd.h> 20 21 #include "ftp_var.h" 22 23 int intr(); 24 int lostpeer(); 25 extern char *home; 26 27 main(argc, argv) 28 char *argv[]; 29 { 30 register char *cp; 31 int top; 32 struct passwd *pw; 33 char homedir[MAXPATHLEN]; 34 35 sp = getservbyname("ftp", "tcp"); 36 if (sp == 0) { 37 fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); 38 exit(1); 39 } 40 doglob = 1; 41 interactive = 1; 42 autologin = 1; 43 argc--, argv++; 44 while (argc > 0 && **argv == '-') { 45 for (cp = *argv + 1; *cp; cp++) 46 switch (*cp) { 47 48 case 'd': 49 options |= SO_DEBUG; 50 debug++; 51 break; 52 53 case 'v': 54 verbose++; 55 break; 56 57 case 't': 58 trace++; 59 break; 60 61 case 'i': 62 interactive = 0; 63 break; 64 65 case 'n': 66 autologin = 0; 67 break; 68 69 case 'g': 70 doglob = 0; 71 break; 72 73 default: 74 fprintf(stderr, 75 "ftp: %c: unknown option\n", *cp); 76 exit(1); 77 } 78 argc--, argv++; 79 } 80 fromatty = isatty(fileno(stdin)); 81 /* 82 * Set up defaults for FTP. 83 */ 84 strcpy(typename, "ascii"), type = TYPE_A; 85 strcpy(formname, "non-print"), form = FORM_N; 86 strcpy(modename, "stream"), mode = MODE_S; 87 strcpy(structname, "file"), stru = STRU_F; 88 strcpy(bytename, "8"), bytesize = 8; 89 if (fromatty) 90 verbose++; 91 /* 92 * Set up the home directory in case we're globbing. 93 */ 94 pw = getpwnam(getlogin()); 95 if (pw == NULL) 96 pw = getpwuid(getuid()); 97 if (pw != NULL) { 98 home = homedir; 99 strcpy(home, pw->pw_dir); 100 } 101 if (argc > 0) { 102 if (setjmp(toplevel)) 103 exit(0); 104 signal(SIGINT, intr); 105 signal(SIGPIPE, lostpeer); 106 setpeer(argc + 1, argv - 1); 107 } 108 top = setjmp(toplevel) == 0; 109 if (top) { 110 signal(SIGINT, intr); 111 signal(SIGPIPE, lostpeer); 112 } 113 for (;;) { 114 cmdscanner(top); 115 top = 1; 116 } 117 } 118 119 intr() 120 { 121 122 longjmp(toplevel, 1); 123 } 124 125 lostpeer() 126 { 127 extern FILE *cout; 128 extern int data; 129 130 if (connected) { 131 if (cout != NULL) { 132 shutdown(fileno(cout), 1+1); 133 fclose(cout); 134 cout = NULL; 135 } 136 if (data >= 0) { 137 shutdown(data, 1+1); 138 (void) close(data); 139 data = -1; 140 } 141 connected = 0; 142 } 143 longjmp(toplevel, 1); 144 } 145 146 char * 147 tail(filename) 148 char *filename; 149 { 150 register char *s; 151 152 while (*filename) { 153 s = rindex(filename, '/'); 154 if (s == NULL) 155 break; 156 if (s[1]) 157 return (s + 1); 158 *s = '\0'; 159 } 160 return (filename); 161 } 162 163 /* 164 * Command parser. 165 */ 166 cmdscanner(top) 167 int top; 168 { 169 register struct cmd *c; 170 struct cmd *getcmd(); 171 extern struct cmd cmdtab[]; 172 extern int help(); 173 174 if (!top) 175 putchar('\n'); 176 for (;;) { 177 if (fromatty) { 178 printf("ftp> "); 179 fflush(stdout); 180 } 181 if (gets(line) == 0) { 182 if (feof(stdin)) { 183 if (!fromatty) 184 quit(); 185 clearerr(stdin); 186 putchar('\n'); 187 } 188 break; 189 } 190 if (line[0] == 0) 191 break; 192 makeargv(); 193 c = getcmd(margv[0]); 194 if (c == (struct cmd *)-1) { 195 printf("?Ambiguous command\n"); 196 continue; 197 } 198 if (c == 0) { 199 printf("?Invalid command\n"); 200 continue; 201 } 202 if (c->c_conn && !connected) { 203 printf ("Not connected.\n"); 204 continue; 205 } 206 (*c->c_handler)(margc, margv); 207 if (bell && c->c_bell) 208 putchar(CTRL(g)); 209 if (c->c_handler != help) 210 break; 211 } 212 longjmp(toplevel, 0); 213 } 214 215 struct cmd * 216 getcmd(name) 217 register char *name; 218 { 219 register char *p, *q; 220 register struct cmd *c, *found; 221 register int nmatches, longest; 222 223 longest = 0; 224 nmatches = 0; 225 found = 0; 226 for (c = cmdtab; p = c->c_name; c++) { 227 for (q = name; *q == *p++; q++) 228 if (*q == 0) /* exact match? */ 229 return (c); 230 if (!*q) { /* the name was a prefix */ 231 if (q - name > longest) { 232 longest = q - name; 233 nmatches = 1; 234 found = c; 235 } else if (q - name == longest) 236 nmatches++; 237 } 238 } 239 if (nmatches > 1) 240 return ((struct cmd *)-1); 241 return (found); 242 } 243 244 /* 245 * Slice a string up into argc/argv. 246 */ 247 makeargv() 248 { 249 char **argp; 250 char *slurpstring(); 251 252 margc = 0; 253 argp = margv; 254 stringbase = line; /* scan from first of buffer */ 255 argbase = argbuf; /* store from first of buffer */ 256 while (*argp++ = slurpstring()) 257 margc++; 258 } 259 260 /* 261 * Parse string into argbuf; 262 * implemented with FSM to 263 * handle quoting and strings 264 */ 265 char * 266 slurpstring() 267 { 268 int got_one = 0; 269 register char *sb = stringbase; 270 register char *ap = argbase; 271 char *tmp = argbase; /* will return this if token found */ 272 273 if (*sb == '!') { /* recognize ! as a token for shell */ 274 stringbase++; 275 return ("!"); 276 } 277 S0: 278 switch (*sb) { 279 280 case '\0': 281 goto OUT; 282 283 case ' ': 284 case '\t': 285 sb++; goto S0; 286 287 default: 288 goto S1; 289 } 290 291 S1: 292 switch (*sb) { 293 294 case ' ': 295 case '\t': 296 case '\0': 297 goto OUT; /* end of token */ 298 299 case '\\': 300 sb++; goto S2; /* slurp next character */ 301 302 case '"': 303 sb++; goto S3; /* slurp quoted string */ 304 305 default: 306 *ap++ = *sb++; /* add character to token */ 307 got_one = 1; 308 goto S1; 309 } 310 311 S2: 312 switch (*sb) { 313 314 case '\0': 315 goto OUT; 316 317 default: 318 *ap++ = *sb++; 319 got_one = 1; 320 goto S1; 321 } 322 323 S3: 324 switch (*sb) { 325 326 case '\0': 327 goto OUT; 328 329 case '"': 330 sb++; goto S1; 331 332 default: 333 *ap++ = *sb++; 334 got_one = 1; 335 goto S3; 336 } 337 338 OUT: 339 if (got_one) 340 *ap++ = '\0'; 341 argbase = ap; /* update storage pointer */ 342 stringbase = sb; /* update scan pointer */ 343 if (got_one) 344 return(tmp); 345 return((char *)0); 346 } 347 348 #define HELPINDENT (sizeof ("directory")) 349 350 /* 351 * Help command. 352 * Call each command handler with argc == 0 and argv[0] == name. 353 */ 354 help(argc, argv) 355 int argc; 356 char *argv[]; 357 { 358 register struct cmd *c; 359 360 if (argc == 1) { 361 register int i, j, w; 362 int columns, width = 0, lines; 363 extern int NCMDS; 364 365 printf("Commands may be abbreviated. Commands are:\n\n"); 366 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 367 int len = strlen(c->c_name); 368 369 if (len > width) 370 width = len; 371 } 372 width = (width + 8) &~ 7; 373 columns = 80 / width; 374 if (columns == 0) 375 columns = 1; 376 lines = (NCMDS + columns - 1) / columns; 377 for (i = 0; i < lines; i++) { 378 for (j = 0; j < columns; j++) { 379 c = cmdtab + j * lines + i; 380 printf("%s", c->c_name); 381 if (c + lines >= &cmdtab[NCMDS]) { 382 printf("\n"); 383 break; 384 } 385 w = strlen(c->c_name); 386 while (w < width) { 387 w = (w + 8) &~ 7; 388 putchar('\t'); 389 } 390 } 391 } 392 return; 393 } 394 while (--argc > 0) { 395 register char *arg; 396 arg = *++argv; 397 c = getcmd(arg); 398 if (c == (struct cmd *)-1) 399 printf("?Ambiguous help command %s\n", arg); 400 else if (c == (struct cmd *)0) 401 printf("?Invalid help command %s\n", arg); 402 else 403 printf("%-*s\t%s\n", HELPINDENT, 404 c->c_name, c->c_help); 405 } 406 } 407 408 /* 409 * Call routine with argc, argv set from args (terminated by 0). 410 */ 411 /* VARARGS2 */ 412 call(routine, args) 413 int (*routine)(); 414 int args; 415 { 416 register int *argp; 417 register int argc; 418 419 for (argc = 0, argp = &args; *argp++ != 0; argc++) 420 ; 421 (*routine)(argc, &args); 422 } 423