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