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