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