1 #ifndef lint 2 static char sccsid[] = "@(#)main.c 4.9 (Berkeley) 07/18/83"; 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 clearerr(stdin); 184 putchar('\n'); 185 } 186 break; 187 } 188 if (line[0] == 0) 189 break; 190 makeargv(); 191 c = getcmd(margv[0]); 192 if (c == (struct cmd *)-1) { 193 printf("?Ambiguous command\n"); 194 continue; 195 } 196 if (c == 0) { 197 printf("?Invalid command\n"); 198 continue; 199 } 200 if (c->c_conn && !connected) { 201 printf ("Not connected.\n"); 202 continue; 203 } 204 (*c->c_handler)(margc, margv); 205 if (bell && c->c_bell) 206 putchar(CTRL(g)); 207 if (c->c_handler != help) 208 break; 209 } 210 longjmp(toplevel, 0); 211 } 212 213 struct cmd * 214 getcmd(name) 215 register char *name; 216 { 217 register char *p, *q; 218 register struct cmd *c, *found; 219 register int nmatches, longest; 220 221 longest = 0; 222 nmatches = 0; 223 found = 0; 224 for (c = cmdtab; p = c->c_name; c++) { 225 for (q = name; *q == *p++; q++) 226 if (*q == 0) /* exact match? */ 227 return (c); 228 if (!*q) { /* the name was a prefix */ 229 if (q - name > longest) { 230 longest = q - name; 231 nmatches = 1; 232 found = c; 233 } else if (q - name == longest) 234 nmatches++; 235 } 236 } 237 if (nmatches > 1) 238 return ((struct cmd *)-1); 239 return (found); 240 } 241 242 /* 243 * Slice a string up into argc/argv. 244 */ 245 makeargv() 246 { 247 char **argp; 248 char *slurpstring(); 249 250 margc = 0; 251 argp = margv; 252 stringbase = line; /* scan from first of buffer */ 253 argbase = argbuf; /* store from first of buffer */ 254 while (*argp++ = slurpstring()) 255 margc++; 256 } 257 258 /* 259 * Parse string into argbuf; 260 * implemented with FSM to 261 * handle quoting and strings 262 */ 263 char * 264 slurpstring() 265 { 266 int got_one = 0; 267 register char *sb = stringbase; 268 register char *ap = argbase; 269 char *tmp = argbase; /* will return this if token found */ 270 271 if (*sb == '!') { /* recognize ! as a token for shell */ 272 stringbase++; 273 return ("!"); 274 } 275 S0: 276 switch (*sb) { 277 278 case '\0': 279 goto OUT; 280 281 case ' ': 282 case '\t': 283 sb++; goto S0; 284 285 default: 286 goto S1; 287 } 288 289 S1: 290 switch (*sb) { 291 292 case ' ': 293 case '\t': 294 case '\0': 295 goto OUT; /* end of token */ 296 297 case '\\': 298 sb++; goto S2; /* slurp next character */ 299 300 case '"': 301 sb++; goto S3; /* slurp quoted string */ 302 303 default: 304 *ap++ = *sb++; /* add character to token */ 305 got_one = 1; 306 goto S1; 307 } 308 309 S2: 310 switch (*sb) { 311 312 case '\0': 313 goto OUT; 314 315 default: 316 *ap++ = *sb++; 317 got_one = 1; 318 goto S1; 319 } 320 321 S3: 322 switch (*sb) { 323 324 case '\0': 325 goto OUT; 326 327 case '"': 328 sb++; goto S1; 329 330 default: 331 *ap++ = *sb++; 332 got_one = 1; 333 goto S3; 334 } 335 336 OUT: 337 if (got_one) 338 *ap++ = '\0'; 339 argbase = ap; /* update storage pointer */ 340 stringbase = sb; /* update scan pointer */ 341 if (got_one) 342 return(tmp); 343 return((char *)0); 344 } 345 346 #define HELPINDENT (sizeof ("directory")) 347 348 /* 349 * Help command. 350 * Call each command handler with argc == 0 and argv[0] == name. 351 */ 352 help(argc, argv) 353 int argc; 354 char *argv[]; 355 { 356 register struct cmd *c; 357 358 if (argc == 1) { 359 register int i, j, w; 360 int columns, width = 0, lines; 361 extern int NCMDS; 362 363 printf("Commands may be abbreviated. Commands are:\n\n"); 364 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 365 int len = strlen(c->c_name); 366 367 if (len > width) 368 width = len; 369 } 370 width = (width + 8) &~ 7; 371 columns = 80 / width; 372 if (columns == 0) 373 columns = 1; 374 lines = (NCMDS + columns - 1) / columns; 375 for (i = 0; i < lines; i++) { 376 for (j = 0; j < columns; j++) { 377 c = cmdtab + j * lines + i; 378 printf("%s", c->c_name); 379 if (c + lines >= &cmdtab[NCMDS]) { 380 printf("\n"); 381 break; 382 } 383 w = strlen(c->c_name); 384 while (w < width) { 385 w = (w + 8) &~ 7; 386 putchar('\t'); 387 } 388 } 389 } 390 return; 391 } 392 while (--argc > 0) { 393 register char *arg; 394 arg = *++argv; 395 c = getcmd(arg); 396 if (c == (struct cmd *)-1) 397 printf("?Ambiguous help command %s\n", arg); 398 else if (c == (struct cmd *)0) 399 printf("?Invalid help command %s\n", arg); 400 else 401 printf("%-*s\t%s\n", HELPINDENT, 402 c->c_name, c->c_help); 403 } 404 } 405 406 /* 407 * Call routine with argc, argv set from args (terminated by 0). 408 */ 409 /* VARARGS2 */ 410 call(routine, args) 411 int (*routine)(); 412 int args; 413 { 414 register int *argp; 415 register int argc; 416 417 for (argc = 0, argp = &args; *argp++ != 0; argc++) 418 ; 419 (*routine)(argc, &args); 420 } 421