1 /* main.c 4.2 82/10/08 */ 2 3 /* 4 * TFTP User Program -- Command Interface. 5 */ 6 #include <sys/types.h> 7 #include <net/in.h> 8 #include <sys/socket.h> 9 #include <signal.h> 10 #include <stdio.h> 11 #include <errno.h> 12 #include <setjmp.h> 13 #include <ctype.h> 14 #include <netdb.h> 15 16 struct sockaddr_in sin = { AF_INET }; 17 int f; 18 int options; 19 int trace; 20 int verbose; 21 int connected; 22 char mode[32]; 23 char line[200]; 24 int margc; 25 char *margv[20]; 26 char *prompt = "tftp"; 27 jmp_buf toplevel; 28 int intr(); 29 struct servent *sp; 30 31 int quit(), help(), setverbose(), settrace(), status(); 32 int get(), put(), setpeer(), setmode(); 33 34 #define HELPINDENT (sizeof("connect")) 35 36 struct cmd { 37 char *name; 38 char *help; 39 int (*handler)(); 40 }; 41 42 char vhelp[] = "toggle verbose mode"; 43 char thelp[] = "toggle packet tracing"; 44 char chelp[] = "connect to remote tftp"; 45 char qhelp[] = "exit tftp"; 46 char hhelp[] = "print help information"; 47 char shelp[] = "send file"; 48 char rhelp[] = "receive file"; 49 char mhelp[] = "set file transfer mode"; 50 char sthelp[] = "show current status"; 51 52 struct cmd cmdtab[] = { 53 { "connect", chelp, setpeer }, 54 { "mode", mhelp, setmode }, 55 { "put", shelp, put }, 56 { "get", rhelp, get }, 57 { "quit", qhelp, quit }, 58 { "verbose", vhelp, setverbose }, 59 { "trace", thelp, settrace }, 60 { "status", sthelp, status }, 61 { "?", hhelp, help }, 62 0 63 }; 64 65 struct cmd *getcmd(); 66 char *tail(); 67 char *index(); 68 char *rindex(); 69 70 main(argc, argv) 71 char *argv[]; 72 { 73 sp = getservbyname("tftp", "udp"); 74 if (sp == 0) { 75 fprintf(stderr, "tftp: udp/tftp: unknown service\n"); 76 exit(1); 77 } 78 sin.sin_port = htons(sp->s_port); 79 if (argc > 1 && !strcmp(argv[1], "-d")) { 80 options |= SO_DEBUG; 81 argc--, argv++; 82 } 83 f = socket(SOCK_DGRAM, 0, 0, options); 84 if (f < 0) { 85 perror("socket"); 86 exit(3); 87 } 88 strcpy(mode, "netascii"); 89 if (argc > 1) { 90 if (setjmp(toplevel) != 0) 91 exit(0); 92 setpeer(argc, argv); 93 } 94 setjmp(toplevel); 95 for (;;) 96 command(1); 97 } 98 99 char *hostname; 100 char hnamebuf[32]; 101 102 setpeer(argc, argv) 103 int argc; 104 char *argv[]; 105 { 106 register int c; 107 struct hostent *host; 108 109 if (argc < 2) { 110 strcpy(line, "Connect "); 111 printf("(to) "); 112 gets(&line[strlen(line)]); 113 makeargv(); 114 argc = margc; 115 argv = margv; 116 } 117 if (argc > 3) { 118 printf("usage: %s host-name [port]\n", argv[0]); 119 return; 120 } 121 host = gethostbyname(argv[1]); 122 if (host) { 123 bcopy(host->h_addr, &sin.sin_addr, host->h_length); 124 hostname = host->h_name; 125 } else { 126 sin.sin_addr.s_addr = inet_addr(argv[1]); 127 if (sin.sin_addr.s_addr == -1) { 128 connected = 0; 129 printf("%s: unknown host\n", argv[1]); 130 return; 131 } 132 strcpy(hnamebuf, argv[1]); 133 hostname = hnamebuf; 134 } 135 sin.sin_port = sp->s_port; 136 if (argc == 3) { 137 sin.sin_port = atoi(argv[2]); 138 if (sin.sin_port < 0) { 139 printf("%s: bad port number\n", argv[2]); 140 connected = 0; 141 return; 142 } 143 } 144 #if vax || pdp11 145 sin.sin_port = htons(sin.sin_port); 146 #endif 147 connected = 1; 148 } 149 150 struct modes { 151 char *m_name; 152 char *m_mode; 153 } modes[] = { 154 { "ascii", "netascii" }, 155 { "binary", "octect" }, 156 { "mail", "mail" }, 157 { 0, 0 } 158 }; 159 160 setmode(argc, argv) 161 char *argv[]; 162 { 163 register struct modes *p; 164 165 if (argc > 2) { 166 char *sep; 167 168 printf("usage: %s [", argv[0]); 169 sep = " "; 170 for (p = modes; p->m_name; p++) { 171 printf("%s%s", sep, p->m_name); 172 if (*sep == ' ') 173 sep = " | "; 174 } 175 printf(" ]\n"); 176 return; 177 } 178 if (argc < 2) { 179 printf("Using %s mode to transfer files.\n", mode); 180 return; 181 } 182 for (p = modes; p->m_name; p++) 183 if (strcmp(argv[1], p->m_name) == 0) 184 break; 185 if (p->m_name) 186 strcpy(mode, p->m_mode); 187 else 188 printf("%s: unknown mode\n", argv[1]); 189 } 190 191 /* 192 * Send file(s). 193 */ 194 put(argc, argv) 195 char *argv[]; 196 { 197 int fd; 198 register int n, addr; 199 register char *cp, *targ; 200 201 if (argc < 2) { 202 strcpy(line, "send "); 203 printf("(file) "); 204 gets(&line[strlen(line)]); 205 makeargv(); 206 argc = margc; 207 argv = margv; 208 } 209 if (argc < 2) { 210 putusage(argv[0]); 211 return; 212 } 213 targ = argv[argc - 1]; 214 if (index(argv[argc - 1], ':')) { 215 char *cp; 216 struct hostent *hp; 217 218 for (n = 1; n < argc - 1; n++) 219 if (index(argv[n], ':')) { 220 putusage(argv[0]); 221 return; 222 } 223 cp = argv[argc - 1]; 224 targ = index(cp, ':'); 225 *targ++ = 0; 226 hp = gethostbyname(cp); 227 if (hp == 0) { 228 printf("%s: Unknown host.\n", cp); 229 return; 230 } 231 bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); 232 sin.sin_family = hp->h_addrtype; 233 connected = 1; 234 hostname = hp->h_name; 235 } 236 if (!connected) { 237 printf("No target machine specified.\n"); 238 return; 239 } 240 sigset(SIGINT, intr); 241 if (argc < 4) { 242 cp = argc == 2 ? tail(targ) : argv[1]; 243 fd = open(cp); 244 if (fd < 0) { 245 perror(cp); 246 return; 247 } 248 sendfile(fd, targ); 249 return; 250 } 251 cp = index(targ, '\0'); 252 *cp++ = '/'; 253 for (n = 1; n < argc - 1; n++) { 254 strcpy(cp, tail(argv[n])); 255 fd = open(argv[n], 0); 256 if (fd < 0) { 257 perror(argv[n]); 258 continue; 259 } 260 sendfile(fd, targ); 261 } 262 } 263 264 putusage(s) 265 char *s; 266 { 267 printf("usage: %s file ... host:target, or\n", s); 268 printf(" %s file ... target (when already connected)\n", s); 269 } 270 271 /* 272 * Receive file(s). 273 */ 274 get(argc, argv) 275 char *argv[]; 276 { 277 int fd; 278 register int n, addr; 279 register char *cp; 280 char *src; 281 282 if (argc < 2) { 283 strcpy(line, "get "); 284 printf("(files) "); 285 gets(&line[strlen(line)]); 286 makeargv(); 287 argc = margc; 288 argv = margv; 289 } 290 if (argc < 2) { 291 getusage(argv[0]); 292 return; 293 } 294 if (!connected) 295 for (n = 1; n < argc - 1; n++) 296 if (index(argv[n], ':') == 0) { 297 getusage(argv[0]); 298 return; 299 } 300 sigset(SIGINT, intr); 301 for (n = 1; argc == 2 || n < argc - 1; n++) { 302 src = index(argv[n], ':'); 303 if (src == NULL) 304 src = argv[n]; 305 else { 306 struct hostent *hp; 307 308 *src++ = 0; 309 hp = gethostbyname(argv[n]); 310 if (hp == 0) { 311 printf("%s: Unknown host.\n", argv[n]); 312 continue; 313 } 314 bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); 315 sin.sin_family = hp->h_addrtype; 316 connected = 1; 317 hostname = hp->h_name; 318 } 319 if (argc < 4) { 320 cp = argc == 3 ? argv[2] : tail(src); 321 fd = creat(cp, 0644); 322 if (fd < 0) { 323 perror(cp); 324 return; 325 } 326 recvfile(fd, src); 327 break; 328 } 329 cp = index(argv[argc - 1], '\0'); 330 *cp++ = '/'; 331 strcpy(cp, tail(src)); 332 fd = creat(src, 0644); 333 if (fd < 0) { 334 perror(src); 335 continue; 336 } 337 recvfile(fd, src); 338 } 339 } 340 341 getusage(s) 342 { 343 printf("usage: %s host:file host:file ... file, or\n", s); 344 printf(" %s file file ... file if connected\n", s); 345 } 346 347 status(argc, argv) 348 char *argv[]; 349 { 350 if (connected) 351 printf("Connected to %s.\n", hostname); 352 else 353 printf("Not connected.\n"); 354 printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 355 verbose ? "on" : "off", trace ? "on" : "off"); 356 } 357 358 intr() 359 { 360 longjmp(toplevel, -1); 361 } 362 363 char * 364 tail(filename) 365 char *filename; 366 { 367 register char *s; 368 369 while (*filename) { 370 s = rindex(filename, '/'); 371 if (s == NULL) 372 break; 373 if (s[1]) 374 return (s + 1); 375 *s = '\0'; 376 } 377 return (filename); 378 } 379 380 /* 381 * Command parser. 382 */ 383 command(top) 384 int top; 385 { 386 register struct cmd *c; 387 388 if (!top) 389 putchar('\n'); 390 else 391 sigset(SIGINT, SIG_DFL); 392 for (;;) { 393 printf("%s> ", prompt); 394 if (gets(line) == 0) 395 break; 396 if (line[0] == 0) 397 break; 398 makeargv(); 399 c = getcmd(margv[0]); 400 if (c == (struct cmd *)-1) { 401 printf("?Ambiguous command\n"); 402 continue; 403 } 404 if (c == 0) { 405 printf("?Invalid command\n"); 406 continue; 407 } 408 (*c->handler)(margc, margv); 409 if (c->handler != help) 410 break; 411 } 412 longjmp(toplevel, 1); 413 } 414 415 struct cmd * 416 getcmd(name) 417 register char *name; 418 { 419 register char *p, *q; 420 register struct cmd *c, *found; 421 register int nmatches, longest; 422 423 longest = 0; 424 nmatches = 0; 425 found = 0; 426 for (c = cmdtab; p = c->name; c++) { 427 for (q = name; *q == *p++; q++) 428 if (*q == 0) /* exact match? */ 429 return (c); 430 if (!*q) { /* the name was a prefix */ 431 if (q - name > longest) { 432 longest = q - name; 433 nmatches = 1; 434 found = c; 435 } else if (q - name == longest) 436 nmatches++; 437 } 438 } 439 if (nmatches > 1) 440 return ((struct cmd *)-1); 441 return (found); 442 } 443 444 /* 445 * Slice a string up into argc/argv. 446 */ 447 makeargv() 448 { 449 register char *cp; 450 register char **argp = margv; 451 452 margc = 0; 453 for (cp = line; *cp;) { 454 while (isspace(*cp)) 455 cp++; 456 if (*cp == '\0') 457 break; 458 *argp++ = cp; 459 margc += 1; 460 while (*cp != '\0' && !isspace(*cp)) 461 cp++; 462 if (*cp == '\0') 463 break; 464 *cp++ = '\0'; 465 } 466 *argp++ = 0; 467 } 468 469 /*VARARGS*/ 470 quit() 471 { 472 exit(0); 473 } 474 475 /* 476 * Help command. 477 * Call each command handler with argc == 0 and argv[0] == name. 478 */ 479 help(argc, argv) 480 int argc; 481 char *argv[]; 482 { 483 register struct cmd *c; 484 485 if (argc == 1) { 486 printf("Commands may be abbreviated. Commands are:\n\n"); 487 for (c = cmdtab; c->name; c++) 488 printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 489 return; 490 } 491 while (--argc > 0) { 492 register char *arg; 493 arg = *++argv; 494 c = getcmd(arg); 495 if (c == (struct cmd *)-1) 496 printf("?Ambiguous help command %s\n", arg); 497 else if (c == (struct cmd *)0) 498 printf("?Invalid help command %s\n", arg); 499 else 500 printf("%s\n", c->help); 501 } 502 } 503 504 /* 505 * Call routine with argc, argv set from args (terminated by 0). 506 */ 507 /* VARARGS2 */ 508 call(routine, args) 509 int (*routine)(); 510 int args; 511 { 512 register int *argp; 513 register int argc; 514 515 for (argc = 0, argp = &args; *argp++ != 0; argc++) 516 ; 517 (*routine)(argc, &args); 518 } 519 520 /*VARARGS*/ 521 settrace() 522 { 523 trace = !trace; 524 printf("Packet tracing %s.\n", trace ? "on" : "off"); 525 } 526 527 /*VARARGS*/ 528 setverbose() 529 { 530 verbose = !verbose; 531 printf("Verbose mode %s.\n", verbose ? "on" : "off"); 532 } 533