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