1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)utilities.c 8.3 (Berkeley) 5/30/95 34 * $FreeBSD: src/usr.bin/telnet/utilities.c,v 1.3.12.1 2002/04/13 11:07:13 markm Exp $ 35 * $DragonFly: src/usr.bin/telnet/utilities.c,v 1.3 2007/11/25 01:28:23 swildner Exp $ 36 */ 37 38 #define TELOPTS 39 #define TELCMDS 40 #define SLC_NAMES 41 #include <arpa/telnet.h> 42 #include <sys/types.h> 43 #include <sys/socket.h> 44 #include <sys/time.h> 45 #include <ctype.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 49 #include "general.h" 50 51 #include "fdset.h" 52 53 #include "ring.h" 54 55 #include "defines.h" 56 57 #include "externs.h" 58 59 60 FILE *NetTrace = 0; /* Not in bss, since needs to stay */ 61 int prettydump; 62 63 /* 64 * upcase() 65 * 66 * Upcase (in place) the argument. 67 */ 68 69 void 70 upcase(char *argument) 71 { 72 int c; 73 74 while ((c = *argument) != 0) { 75 if (islower(c)) { 76 *argument = toupper(c); 77 } 78 argument++; 79 } 80 } 81 82 /* 83 * SetSockOpt() 84 * 85 * Compensate for differences in 4.2 and 4.3 systems. 86 */ 87 88 int 89 SetSockOpt(int fd, int level, int option, int yesno) 90 { 91 return setsockopt(fd, level, option, 92 (char *)&yesno, sizeof yesno); 93 } 94 95 /* 96 * The following are routines used to print out debugging information. 97 */ 98 99 unsigned char NetTraceFile[256] = "(standard output)"; 100 101 void 102 SetNetTrace(char *file) 103 { 104 if (NetTrace && NetTrace != stdout) 105 fclose(NetTrace); 106 if (file && (strcmp(file, "-") != 0)) { 107 NetTrace = fopen(file, "w"); 108 if (NetTrace) { 109 strcpy((char *)NetTraceFile, file); 110 return; 111 } 112 fprintf(stderr, "Cannot open %s.\n", file); 113 } 114 NetTrace = stdout; 115 strcpy((char *)NetTraceFile, "(standard output)"); 116 } 117 118 void 119 Dump(char direction, unsigned char *buffer, int length) 120 { 121 # define BYTES_PER_LINE 32 122 # define min(x,y) ((x<y)? x:y) 123 unsigned char *pThis; 124 int offset; 125 126 offset = 0; 127 128 while (length) { 129 /* print one line */ 130 fprintf(NetTrace, "%c 0x%x\t", direction, offset); 131 pThis = buffer; 132 if (prettydump) { 133 buffer = buffer + min(length, BYTES_PER_LINE/2); 134 while (pThis < buffer) { 135 fprintf(NetTrace, "%c%.2x", 136 (((*pThis)&0xff) == 0xff) ? '*' : ' ', 137 (*pThis)&0xff); 138 pThis++; 139 } 140 length -= BYTES_PER_LINE/2; 141 offset += BYTES_PER_LINE/2; 142 } else { 143 buffer = buffer + min(length, BYTES_PER_LINE); 144 while (pThis < buffer) { 145 fprintf(NetTrace, "%.2x", (*pThis)&0xff); 146 pThis++; 147 } 148 length -= BYTES_PER_LINE; 149 offset += BYTES_PER_LINE; 150 } 151 if (NetTrace == stdout) { 152 fprintf(NetTrace, "\r\n"); 153 } else { 154 fprintf(NetTrace, "\n"); 155 } 156 if (length < 0) { 157 fflush(NetTrace); 158 return; 159 } 160 /* find next unique line */ 161 } 162 fflush(NetTrace); 163 } 164 165 166 void 167 printoption(const char *direction, int cmd, int option) 168 { 169 if (!showoptions) 170 return; 171 if (cmd == IAC) { 172 if (TELCMD_OK(option)) 173 fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option)); 174 else 175 fprintf(NetTrace, "%s IAC %d", direction, option); 176 } else { 177 const char *fmt; 178 fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : 179 (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; 180 if (fmt) { 181 fprintf(NetTrace, "%s %s ", direction, fmt); 182 if (TELOPT_OK(option)) 183 fprintf(NetTrace, "%s", TELOPT(option)); 184 else if (option == TELOPT_EXOPL) 185 fprintf(NetTrace, "EXOPL"); 186 else 187 fprintf(NetTrace, "%d", option); 188 } else 189 fprintf(NetTrace, "%s %d %d", direction, cmd, option); 190 } 191 if (NetTrace == stdout) { 192 fprintf(NetTrace, "\r\n"); 193 fflush(NetTrace); 194 } else { 195 fprintf(NetTrace, "\n"); 196 } 197 return; 198 } 199 200 void 201 optionstatus(void) 202 { 203 int i; 204 extern char will_wont_resp[], do_dont_resp[]; 205 206 for (i = 0; i < 256; i++) { 207 if (do_dont_resp[i]) { 208 if (TELOPT_OK(i)) 209 printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]); 210 else if (TELCMD_OK(i)) 211 printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]); 212 else 213 printf("resp DO_DONT %d: %d\n", i, 214 do_dont_resp[i]); 215 if (my_want_state_is_do(i)) { 216 if (TELOPT_OK(i)) 217 printf("want DO %s\n", TELOPT(i)); 218 else if (TELCMD_OK(i)) 219 printf("want DO %s\n", TELCMD(i)); 220 else 221 printf("want DO %d\n", i); 222 } else { 223 if (TELOPT_OK(i)) 224 printf("want DONT %s\n", TELOPT(i)); 225 else if (TELCMD_OK(i)) 226 printf("want DONT %s\n", TELCMD(i)); 227 else 228 printf("want DONT %d\n", i); 229 } 230 } else { 231 if (my_state_is_do(i)) { 232 if (TELOPT_OK(i)) 233 printf(" DO %s\n", TELOPT(i)); 234 else if (TELCMD_OK(i)) 235 printf(" DO %s\n", TELCMD(i)); 236 else 237 printf(" DO %d\n", i); 238 } 239 } 240 if (will_wont_resp[i]) { 241 if (TELOPT_OK(i)) 242 printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]); 243 else if (TELCMD_OK(i)) 244 printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]); 245 else 246 printf("resp WILL_WONT %d: %d\n", 247 i, will_wont_resp[i]); 248 if (my_want_state_is_will(i)) { 249 if (TELOPT_OK(i)) 250 printf("want WILL %s\n", TELOPT(i)); 251 else if (TELCMD_OK(i)) 252 printf("want WILL %s\n", TELCMD(i)); 253 else 254 printf("want WILL %d\n", i); 255 } else { 256 if (TELOPT_OK(i)) 257 printf("want WONT %s\n", TELOPT(i)); 258 else if (TELCMD_OK(i)) 259 printf("want WONT %s\n", TELCMD(i)); 260 else 261 printf("want WONT %d\n", i); 262 } 263 } else { 264 if (my_state_is_will(i)) { 265 if (TELOPT_OK(i)) 266 printf(" WILL %s\n", TELOPT(i)); 267 else if (TELCMD_OK(i)) 268 printf(" WILL %s\n", TELCMD(i)); 269 else 270 printf(" WILL %d\n", i); 271 } 272 } 273 } 274 275 } 276 277 void 278 printsub(char direction, unsigned char *pointer, int length) 279 { 280 int i; 281 extern int want_status_response; 282 283 if (showoptions || direction == 0 || 284 (want_status_response && (pointer[0] == TELOPT_STATUS))) { 285 if (direction) { 286 fprintf(NetTrace, "%s IAC SB ", 287 (direction == '<')? "RCVD":"SENT"); 288 if (length >= 3) { 289 int j; 290 291 i = pointer[length-2]; 292 j = pointer[length-1]; 293 294 if (i != IAC || j != SE) { 295 fprintf(NetTrace, "(terminated by "); 296 if (TELOPT_OK(i)) 297 fprintf(NetTrace, "%s ", TELOPT(i)); 298 else if (TELCMD_OK(i)) 299 fprintf(NetTrace, "%s ", TELCMD(i)); 300 else 301 fprintf(NetTrace, "%d ", i); 302 if (TELOPT_OK(j)) 303 fprintf(NetTrace, "%s", TELOPT(j)); 304 else if (TELCMD_OK(j)) 305 fprintf(NetTrace, "%s", TELCMD(j)); 306 else 307 fprintf(NetTrace, "%d", j); 308 fprintf(NetTrace, ", not IAC SE!) "); 309 } 310 } 311 length -= 2; 312 } 313 if (length < 1) { 314 fprintf(NetTrace, "(Empty suboption??\?)"); 315 if (NetTrace == stdout) 316 fflush(NetTrace); 317 return; 318 } 319 switch (pointer[0]) { 320 case TELOPT_TTYPE: 321 fprintf(NetTrace, "TERMINAL-TYPE "); 322 switch (pointer[1]) { 323 case TELQUAL_IS: 324 fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); 325 break; 326 case TELQUAL_SEND: 327 fprintf(NetTrace, "SEND"); 328 break; 329 default: 330 fprintf(NetTrace, 331 "- unknown qualifier %d (0x%x).", 332 pointer[1], pointer[1]); 333 } 334 break; 335 case TELOPT_TSPEED: 336 fprintf(NetTrace, "TERMINAL-SPEED"); 337 if (length < 2) { 338 fprintf(NetTrace, " (empty suboption??\?)"); 339 break; 340 } 341 switch (pointer[1]) { 342 case TELQUAL_IS: 343 fprintf(NetTrace, " IS "); 344 fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); 345 break; 346 default: 347 if (pointer[1] == 1) 348 fprintf(NetTrace, " SEND"); 349 else 350 fprintf(NetTrace, " %d (unknown)", pointer[1]); 351 for (i = 2; i < length; i++) 352 fprintf(NetTrace, " ?%d?", pointer[i]); 353 break; 354 } 355 break; 356 357 case TELOPT_LFLOW: 358 fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); 359 if (length < 2) { 360 fprintf(NetTrace, " (empty suboption??\?)"); 361 break; 362 } 363 switch (pointer[1]) { 364 case LFLOW_OFF: 365 fprintf(NetTrace, " OFF"); break; 366 case LFLOW_ON: 367 fprintf(NetTrace, " ON"); break; 368 case LFLOW_RESTART_ANY: 369 fprintf(NetTrace, " RESTART-ANY"); break; 370 case LFLOW_RESTART_XON: 371 fprintf(NetTrace, " RESTART-XON"); break; 372 default: 373 fprintf(NetTrace, " %d (unknown)", pointer[1]); 374 } 375 for (i = 2; i < length; i++) 376 fprintf(NetTrace, " ?%d?", pointer[i]); 377 break; 378 379 case TELOPT_NAWS: 380 fprintf(NetTrace, "NAWS"); 381 if (length < 2) { 382 fprintf(NetTrace, " (empty suboption??\?)"); 383 break; 384 } 385 if (length == 2) { 386 fprintf(NetTrace, " ?%d?", pointer[1]); 387 break; 388 } 389 fprintf(NetTrace, " %d %d (%d)", 390 pointer[1], pointer[2], 391 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 392 if (length == 4) { 393 fprintf(NetTrace, " ?%d?", pointer[3]); 394 break; 395 } 396 fprintf(NetTrace, " %d %d (%d)", 397 pointer[3], pointer[4], 398 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 399 for (i = 5; i < length; i++) 400 fprintf(NetTrace, " ?%d?", pointer[i]); 401 break; 402 403 404 405 case TELOPT_LINEMODE: 406 fprintf(NetTrace, "LINEMODE "); 407 if (length < 2) { 408 fprintf(NetTrace, " (empty suboption??\?)"); 409 break; 410 } 411 switch (pointer[1]) { 412 case WILL: 413 fprintf(NetTrace, "WILL "); 414 goto common; 415 case WONT: 416 fprintf(NetTrace, "WONT "); 417 goto common; 418 case DO: 419 fprintf(NetTrace, "DO "); 420 goto common; 421 case DONT: 422 fprintf(NetTrace, "DONT "); 423 common: 424 if (length < 3) { 425 fprintf(NetTrace, "(no option??\?)"); 426 break; 427 } 428 switch (pointer[2]) { 429 case LM_FORWARDMASK: 430 fprintf(NetTrace, "Forward Mask"); 431 for (i = 3; i < length; i++) 432 fprintf(NetTrace, " %x", pointer[i]); 433 break; 434 default: 435 fprintf(NetTrace, "%d (unknown)", pointer[2]); 436 for (i = 3; i < length; i++) 437 fprintf(NetTrace, " %d", pointer[i]); 438 break; 439 } 440 break; 441 442 case LM_SLC: 443 fprintf(NetTrace, "SLC"); 444 for (i = 2; i < length - 2; i += 3) { 445 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 446 fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); 447 else 448 fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); 449 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 450 case SLC_NOSUPPORT: 451 fprintf(NetTrace, " NOSUPPORT"); break; 452 case SLC_CANTCHANGE: 453 fprintf(NetTrace, " CANTCHANGE"); break; 454 case SLC_VARIABLE: 455 fprintf(NetTrace, " VARIABLE"); break; 456 case SLC_DEFAULT: 457 fprintf(NetTrace, " DEFAULT"); break; 458 } 459 fprintf(NetTrace, "%s%s%s", 460 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 461 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 462 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 463 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 464 SLC_FLUSHOUT| SLC_LEVELBITS)) 465 fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); 466 fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); 467 if ((pointer[i+SLC_VALUE] == IAC) && 468 (pointer[i+SLC_VALUE+1] == IAC)) 469 i++; 470 } 471 for (; i < length; i++) 472 fprintf(NetTrace, " ?%d?", pointer[i]); 473 break; 474 475 case LM_MODE: 476 fprintf(NetTrace, "MODE "); 477 if (length < 3) { 478 fprintf(NetTrace, "(no mode??\?)"); 479 break; 480 } 481 { 482 char tbuf[64]; 483 sprintf(tbuf, "%s%s%s%s%s", 484 pointer[2]&MODE_EDIT ? "|EDIT" : "", 485 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 486 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 487 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 488 pointer[2]&MODE_ACK ? "|ACK" : ""); 489 fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); 490 } 491 if (pointer[2]&~(MODE_MASK)) 492 fprintf(NetTrace, " (0x%x)", pointer[2]); 493 for (i = 3; i < length; i++) 494 fprintf(NetTrace, " ?0x%x?", pointer[i]); 495 break; 496 default: 497 fprintf(NetTrace, "%d (unknown)", pointer[1]); 498 for (i = 2; i < length; i++) 499 fprintf(NetTrace, " %d", pointer[i]); 500 } 501 break; 502 503 case TELOPT_STATUS: { 504 const char *cp; 505 int j, k; 506 507 fprintf(NetTrace, "STATUS"); 508 509 switch (pointer[1]) { 510 default: 511 if (pointer[1] == TELQUAL_SEND) 512 fprintf(NetTrace, " SEND"); 513 else 514 fprintf(NetTrace, " %d (unknown)", pointer[1]); 515 for (i = 2; i < length; i++) 516 fprintf(NetTrace, " ?%d?", pointer[i]); 517 break; 518 case TELQUAL_IS: 519 if (--want_status_response < 0) 520 want_status_response = 0; 521 if (NetTrace == stdout) 522 fprintf(NetTrace, " IS\r\n"); 523 else 524 fprintf(NetTrace, " IS\n"); 525 526 for (i = 2; i < length; i++) { 527 switch(pointer[i]) { 528 case DO: cp = "DO"; goto common2; 529 case DONT: cp = "DONT"; goto common2; 530 case WILL: cp = "WILL"; goto common2; 531 case WONT: cp = "WONT"; goto common2; 532 common2: 533 i++; 534 if (TELOPT_OK((int)pointer[i])) 535 fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); 536 else 537 fprintf(NetTrace, " %s %d", cp, pointer[i]); 538 539 if (NetTrace == stdout) 540 fprintf(NetTrace, "\r\n"); 541 else 542 fprintf(NetTrace, "\n"); 543 break; 544 545 case SB: 546 fprintf(NetTrace, " SB "); 547 i++; 548 j = k = i; 549 while (j < length) { 550 if (pointer[j] == SE) { 551 if (j+1 == length) 552 break; 553 if (pointer[j+1] == SE) 554 j++; 555 else 556 break; 557 } 558 pointer[k++] = pointer[j++]; 559 } 560 printsub(0, &pointer[i], k - i); 561 if (i < length) { 562 fprintf(NetTrace, " SE"); 563 i = j; 564 } else 565 i = j - 1; 566 567 if (NetTrace == stdout) 568 fprintf(NetTrace, "\r\n"); 569 else 570 fprintf(NetTrace, "\n"); 571 572 break; 573 574 default: 575 fprintf(NetTrace, " %d", pointer[i]); 576 break; 577 } 578 } 579 break; 580 } 581 break; 582 } 583 584 case TELOPT_XDISPLOC: 585 fprintf(NetTrace, "X-DISPLAY-LOCATION "); 586 switch (pointer[1]) { 587 case TELQUAL_IS: 588 fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); 589 break; 590 case TELQUAL_SEND: 591 fprintf(NetTrace, "SEND"); 592 break; 593 default: 594 fprintf(NetTrace, "- unknown qualifier %d (0x%x).", 595 pointer[1], pointer[1]); 596 } 597 break; 598 599 case TELOPT_NEW_ENVIRON: 600 fprintf(NetTrace, "NEW-ENVIRON "); 601 #ifdef OLD_ENVIRON 602 goto env_common1; 603 case TELOPT_OLD_ENVIRON: 604 fprintf(NetTrace, "OLD-ENVIRON"); 605 env_common1: 606 #endif 607 switch (pointer[1]) { 608 case TELQUAL_IS: 609 fprintf(NetTrace, "IS "); 610 goto env_common; 611 case TELQUAL_SEND: 612 fprintf(NetTrace, "SEND "); 613 goto env_common; 614 case TELQUAL_INFO: 615 fprintf(NetTrace, "INFO "); 616 env_common: 617 { 618 int noquote = 2; 619 #if defined(ENV_HACK) && defined(OLD_ENVIRON) 620 extern int old_env_var, old_env_value; 621 #endif 622 for (i = 2; i < length; i++ ) { 623 switch (pointer[i]) { 624 case NEW_ENV_VALUE: 625 #ifdef OLD_ENVIRON 626 /* case NEW_ENV_OVAR: */ 627 if (pointer[0] == TELOPT_OLD_ENVIRON) { 628 # ifdef ENV_HACK 629 if (old_env_var == OLD_ENV_VALUE) 630 fprintf(NetTrace, "\" (VALUE) " + noquote); 631 else 632 # endif 633 fprintf(NetTrace, "\" VAR " + noquote); 634 } else 635 #endif /* OLD_ENVIRON */ 636 fprintf(NetTrace, "\" VALUE " + noquote); 637 noquote = 2; 638 break; 639 640 case NEW_ENV_VAR: 641 #ifdef OLD_ENVIRON 642 /* case OLD_ENV_VALUE: */ 643 if (pointer[0] == TELOPT_OLD_ENVIRON) { 644 # ifdef ENV_HACK 645 if (old_env_value == OLD_ENV_VAR) 646 fprintf(NetTrace, "\" (VAR) " + noquote); 647 else 648 # endif 649 fprintf(NetTrace, "\" VALUE " + noquote); 650 } else 651 #endif /* OLD_ENVIRON */ 652 fprintf(NetTrace, "\" VAR " + noquote); 653 noquote = 2; 654 break; 655 656 case ENV_ESC: 657 fprintf(NetTrace, "\" ESC " + noquote); 658 noquote = 2; 659 break; 660 661 case ENV_USERVAR: 662 fprintf(NetTrace, "\" USERVAR " + noquote); 663 noquote = 2; 664 break; 665 666 default: 667 if (isprint(pointer[i]) && pointer[i] != '"') { 668 if (noquote) { 669 putc('"', NetTrace); 670 noquote = 0; 671 } 672 putc(pointer[i], NetTrace); 673 } else { 674 fprintf(NetTrace, "\" %03o " + noquote, 675 pointer[i]); 676 noquote = 2; 677 } 678 break; 679 } 680 } 681 if (!noquote) 682 putc('"', NetTrace); 683 break; 684 } 685 } 686 break; 687 688 default: 689 if (TELOPT_OK(pointer[0])) 690 fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); 691 else 692 fprintf(NetTrace, "%d (unknown)", pointer[0]); 693 for (i = 1; i < length; i++) 694 fprintf(NetTrace, " %d", pointer[i]); 695 break; 696 } 697 if (direction) { 698 if (NetTrace == stdout) 699 fprintf(NetTrace, "\r\n"); 700 else 701 fprintf(NetTrace, "\n"); 702 } 703 if (NetTrace == stdout) 704 fflush(NetTrace); 705 } 706 } 707 708 /* EmptyTerminal - called to make sure that the terminal buffer is empty. 709 * Note that we consider the buffer to run all the 710 * way to the kernel (thus the select). 711 */ 712 713 static void 714 EmptyTerminal(void) 715 { 716 fd_set o; 717 718 FD_ZERO(&o); 719 720 if (TTYBYTES() == 0) { 721 FD_SET(tout, &o); 722 (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 723 (struct timeval *) 0); /* wait for TTLOWAT */ 724 } else { 725 while (TTYBYTES()) { 726 (void) ttyflush(0); 727 FD_SET(tout, &o); 728 (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, 729 (struct timeval *) 0); /* wait for TTLOWAT */ 730 } 731 } 732 } 733 734 static void 735 SetForExit(void) 736 { 737 setconnmode(0); 738 do { 739 (void)telrcv(); /* Process any incoming data */ 740 EmptyTerminal(); 741 } while (ring_full_count(&netiring)); /* While there is any */ 742 setcommandmode(); 743 fflush(stdout); 744 fflush(stderr); 745 setconnmode(0); 746 EmptyTerminal(); /* Flush the path to the tty */ 747 setcommandmode(); 748 } 749 750 void 751 Exit(int returnCode) 752 { 753 SetForExit(); 754 exit(returnCode); 755 } 756 757 void 758 ExitString(const char *string, int returnCode) 759 { 760 SetForExit(); 761 fwrite(string, 1, strlen(string), stderr); 762 exit(returnCode); 763 } 764