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