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