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