1 #ifndef lint 2 static char sccsid[] = "@(#)main.c 4.3 (Berkeley) 02/23/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 108 if (connected) { 109 if (cout != NULL) { 110 shutdown(fileno(cout), 1+1); 111 fclose(cout); 112 cout = NULL; 113 } 114 if (data >= 0) { 115 shutdown(data, 1+1); 116 (void) close(data); 117 data = -1; 118 } 119 connected = 0; 120 } 121 longjmp(toplevel, 1); 122 } 123 124 char * 125 tail(filename) 126 char *filename; 127 { 128 register char *s; 129 130 while (*filename) { 131 s = rindex(filename, '/'); 132 if (s == NULL) 133 break; 134 if (s[1]) 135 return (s + 1); 136 *s = '\0'; 137 } 138 return (filename); 139 } 140 141 /* 142 * Command parser. 143 */ 144 cmdscanner(top) 145 int top; 146 { 147 register struct cmd *c; 148 struct cmd *getcmd(); 149 extern struct cmd cmdtab[]; 150 extern int help(); 151 152 if (!top) 153 putchar('\n'); 154 for (;;) { 155 if (fromatty) { 156 printf("ftp> "); 157 fflush(stdout); 158 } 159 if (gets(line) == 0) 160 break; 161 if (line[0] == 0) 162 break; 163 makeargv(); 164 c = getcmd(margv[0]); 165 if (c == (struct cmd *)-1) { 166 printf("?Ambiguous command\n"); 167 continue; 168 } 169 if (c == 0) { 170 printf("?Invalid command\n"); 171 continue; 172 } 173 (*c->c_handler)(margc, margv); 174 if (bell && c->c_bell) 175 putchar(CTRL(g)); 176 if (c->c_handler != help) 177 break; 178 } 179 longjmp(toplevel, 0); 180 } 181 182 struct cmd * 183 getcmd(name) 184 register char *name; 185 { 186 register char *p, *q; 187 register struct cmd *c, *found; 188 register int nmatches, longest; 189 190 longest = 0; 191 nmatches = 0; 192 found = 0; 193 for (c = cmdtab; p = c->c_name; c++) { 194 for (q = name; *q == *p++; q++) 195 if (*q == 0) /* exact match? */ 196 return (c); 197 if (!*q) { /* the name was a prefix */ 198 if (q - name > longest) { 199 longest = q - name; 200 nmatches = 1; 201 found = c; 202 } else if (q - name == longest) 203 nmatches++; 204 } 205 } 206 if (nmatches > 1) 207 return ((struct cmd *)-1); 208 return (found); 209 } 210 211 /* 212 * Slice a string up into argc/argv. 213 */ 214 makeargv() 215 { 216 char **argp; 217 char *slurpstring(); 218 219 margc = 0; 220 argp = margv; 221 stringbase = line; /* scan from first of buffer */ 222 argbase = argbuf; /* store from first of buffer */ 223 while (*argp++ = slurpstring()) 224 margc++; 225 } 226 227 /* 228 * Parse string into argbuf; 229 * implemented with FSM to 230 * handle quoting and strings 231 */ 232 char * 233 slurpstring() 234 { 235 int got_one = 0; 236 register char *sb = stringbase; 237 register char *ap = argbase; 238 char *tmp = argbase; /* will return this if token found */ 239 240 S0: 241 switch (*sb) { 242 243 case '\0': 244 goto OUT; 245 246 case ' ': 247 case '\t': 248 sb++; goto S0; 249 250 default: 251 goto S1; 252 } 253 254 S1: 255 switch (*sb) { 256 257 case ' ': 258 case '\t': 259 case '\0': 260 goto OUT; /* end of token */ 261 262 case '\\': 263 sb++; goto S2; /* slurp next character */ 264 265 case '"': 266 sb++; goto S3; /* slurp quoted string */ 267 268 default: 269 *ap++ = *sb++; /* add character to token */ 270 got_one = 1; 271 goto S1; 272 } 273 274 S2: 275 switch (*sb) { 276 277 case '\0': 278 goto OUT; 279 280 default: 281 *ap++ = *sb++; 282 got_one = 1; 283 goto S1; 284 } 285 286 S3: 287 switch (*sb) { 288 289 case '\0': 290 goto OUT; 291 292 case '"': 293 sb++; goto S1; 294 295 default: 296 *ap++ = *sb++; 297 got_one = 1; 298 goto S3; 299 } 300 301 OUT: 302 if (got_one) 303 *ap++ = '\0'; 304 argbase = ap; /* update storage pointer */ 305 stringbase = sb; /* update scan pointer */ 306 if (got_one) 307 return(tmp); 308 return((char *)0); 309 } 310 311 #define HELPINDENT (sizeof ("directory")) 312 313 /* 314 * Help command. 315 * Call each command handler with argc == 0 and argv[0] == name. 316 */ 317 help(argc, argv) 318 int argc; 319 char *argv[]; 320 { 321 register struct cmd *c; 322 323 if (argc == 1) { 324 register int i, j, w; 325 int columns, width = 0, lines; 326 extern int NCMDS; 327 328 printf("Commands may be abbreviated. Commands are:\n\n"); 329 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 330 int len = strlen(c->c_name); 331 332 if (len > width) 333 width = len; 334 } 335 width = (width + 8) &~ 7; 336 columns = 80 / width; 337 if (columns == 0) 338 columns = 1; 339 lines = (NCMDS + columns - 1) / columns; 340 for (i = 0; i < lines; i++) { 341 for (j = 0; j < columns; j++) { 342 c = cmdtab + j * lines + i; 343 printf("%s", c->c_name); 344 if (c + lines >= &cmdtab[NCMDS]) { 345 printf("\n"); 346 break; 347 } 348 w = strlen(c->c_name); 349 while (w < width) { 350 w = (w + 8) &~ 7; 351 putchar('\t'); 352 } 353 } 354 } 355 return; 356 } 357 while (--argc > 0) { 358 register char *arg; 359 arg = *++argv; 360 c = getcmd(arg); 361 if (c == (struct cmd *)-1) 362 printf("?Ambiguous help command %s\n", arg); 363 else if (c == (struct cmd *)0) 364 printf("?Invalid help command %s\n", arg); 365 else 366 printf("%-*s\t%s\n", HELPINDENT, 367 c->c_name, c->c_help); 368 } 369 } 370 371 /* 372 * Call routine with argc, argv set from args (terminated by 0). 373 */ 374 /* VARARGS2 */ 375 call(routine, args) 376 int (*routine)(); 377 int args; 378 { 379 register int *argp; 380 register int argc; 381 382 for (argc = 0, argp = &args; *argp++ != 0; argc++) 383 ; 384 (*routine)(argc, &args); 385 } 386