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