xconsole.c revision bfce1ac2
1/* 2 * 3Copyright 1990, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 * 25 * Author: Keith Packard, MIT X Consortium 26 */ 27 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <X11/Xfuncproto.h> 34 35#include <X11/Intrinsic.h> 36#include <X11/StringDefs.h> 37#include <X11/Xatom.h> 38 39#include <X11/Xmu/Atoms.h> 40#include <X11/Xmu/StdSel.h> 41#include <X11/Xmu/SysUtil.h> 42 43#include <X11/Xaw/Form.h> 44#include <X11/Xaw/Label.h> 45#include <X11/Xaw/Command.h> 46#include <X11/Xaw/AsciiText.h> 47#include <X11/Xaw/Dialog.h> 48#include <X11/Xaw/Cardinals.h> 49#include <X11/Xaw/Paned.h> 50#include <X11/Xaw/Box.h> 51 52extern char *_XawTextGetSTRING(TextWidget ctx, XawTextPosition left, 53 XawTextPosition right); 54 55#include <X11/Xos.h> 56#include <X11/Xfuncs.h> 57#include <sys/stat.h> 58#ifndef _POSIX_SOURCE 59#define _POSIX_SOURCE 60#include <stdio.h> 61#undef _POSIX_SOURCE 62#else 63#include <stdio.h> 64#endif 65#include <X11/Shell.h> 66#include <ctype.h> 67#include <stdlib.h> 68#ifdef HAS_OPENPTY 69# ifdef HAVE_UTIL_H 70# include <util.h> 71# endif 72# ifdef HAVE_LIBUTIL_H 73# include <libutil.h> 74# endif 75# ifdef HAVE_PTY_H 76# include <pty.h> 77# endif 78#endif 79 80static void inputReady(XtPointer w, int *source, XtInputId *id); 81static long TextLength(Widget w); 82static void TextReplace(Widget w, int start, int end, XawTextBlock *block); 83static void TextAppend(Widget w, char *s, int len); 84static void TextInsert(Widget w, char *s, int len); 85static Bool ExceededMaxLines(Widget w); 86static void ScrollLine(Widget w); 87 88static Widget top, text; 89 90static XtInputId input_id; 91 92static FILE *input; 93static Boolean regularFile = FALSE; 94 95static Boolean notified; 96static Boolean iconified; 97 98static Atom wm_delete_window; 99static Atom mit_console; 100 101#define MIT_CONSOLE_LEN 12 102#define MIT_CONSOLE "MIT_CONSOLE_" 103static char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE; 104 105static struct _app_resources { 106 char *file; 107 Boolean stripNonprint; 108 Boolean notify; 109 Boolean daemon; 110 Boolean verbose; 111 Boolean exitOnFail; 112 int saveLines; 113} app_resources; 114 115#define Offset(field) XtOffsetOf(struct _app_resources, field) 116 117static XtResource resources[] = { 118 {"file", "File", XtRString, sizeof (char *), 119 Offset (file), XtRString, "console" }, 120 {"notify", "Notify", XtRBoolean, sizeof (Boolean), 121 Offset (notify), XtRImmediate, (XtPointer)True }, 122 {"stripNonprint", "StripNonprint", XtRBoolean, sizeof (Boolean), 123 Offset (stripNonprint), XtRImmediate, (XtPointer)True }, 124 {"daemon", "Daemon", XtRBoolean, sizeof (Boolean), 125 Offset (daemon), XtRImmediate, (XtPointer)False}, 126 {"verbose", "Verbose", XtRBoolean, sizeof (Boolean), 127 Offset (verbose),XtRImmediate, (XtPointer)False}, 128 {"exitOnFail", "ExitOnFail", XtRBoolean, sizeof (Boolean), 129 Offset (exitOnFail),XtRImmediate, (XtPointer)False}, 130 {"saveLines", "SaveLines", XtRInt, sizeof (int), 131 Offset (saveLines), XtRImmediate, (XtPointer) 0 }, 132}; 133 134#undef Offset 135 136static XrmOptionDescRec options[] = { 137 {"-file", "*file", XrmoptionSepArg, NULL}, 138 {"-notify", "*notify", XrmoptionNoArg, "TRUE"}, 139 {"-nonotify", "*notify", XrmoptionNoArg, "FALSE"}, 140 {"-daemon", "*daemon", XrmoptionNoArg, "TRUE"}, 141 {"-verbose", "*verbose", XrmoptionNoArg, "TRUE"}, 142 {"-exitOnFail", "*exitOnFail", XrmoptionNoArg, "TRUE"}, 143 {"-saveLines", "*saveLines", XrmoptionSepArg, NULL}, 144}; 145 146 147#ifdef linux 148#define USE_FILE 149#define FILE_NAME "/dev/xconsole" 150# if defined (__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) 151/* 152 * Linux distribution based on glibc 2.1 and higher should use 153 * devpts. This is the fallback if open file FILE_NAME fails. 154 * <werner@suse.de> 155 */ 156# define USE_PTS 157# endif 158#endif 159 160#if defined(_AIX) 161# define USE_PTS 162#endif 163 164#if !defined (USE_FILE) || defined (linux) 165# include <sys/ioctl.h> 166# ifdef hpux 167# include <termios.h> 168# endif 169# if defined (SVR4) || defined (USE_PTS) 170# include <termios.h> 171# ifndef HAS_OPENPTY 172# include <sys/stropts.h> /* for I_PUSH */ 173# endif 174# ifdef sun 175# include <sys/strredir.h> 176# endif 177# endif 178# if defined(TIOCCONS) || defined(SRIOCSREDIR) 179# define USE_PTY 180static int tty_fd, pty_fd; 181# endif 182#endif 183 184#if (defined(SVR4) && !defined(sun)) || (defined(SYSV) && defined(i386)) 185#define USE_OSM 186#include <signal.h> 187#endif 188 189#ifdef USE_PTY 190static int get_pty(int *pty, int *tty); 191#endif 192 193#ifdef USE_OSM 194static FILE *osm_pipe(void); 195static int child_pid; 196#endif 197 198/* Copied from xterm/ptyx.h */ 199#ifndef PTYCHAR1 200#ifdef __hpux 201#define PTYCHAR1 "zyxwvutsrqp" 202#else /* !__hpux */ 203#define PTYCHAR1 "pqrstuvwxyzPQRSTUVWXYZ" 204#endif /* !__hpux */ 205#endif /* !PTYCHAR1 */ 206 207#ifndef PTYCHAR2 208#ifdef __hpux 209#define PTYCHAR2 "fedcba9876543210" 210#else /* !__hpux */ 211#ifdef __FreeBSD__ 212#define PTYCHAR2 "0123456789abcdefghijklmnopqrstuv" 213#else /* !__FreeBSD__ */ 214#define PTYCHAR2 "0123456789abcdef" 215#endif /* !__FreeBSD__ */ 216#endif /* !__hpux */ 217#endif /* !PTYCHAR2 */ 218 219static void 220OpenConsole(void) 221{ 222 input = 0; 223 if (app_resources.file) 224 { 225 if (!strcmp (app_resources.file, "console")) 226 { 227 /* must be owner and have read/write permission */ 228#if !defined(__NetBSD__) && !defined(__OpenBSD__) 229 struct stat sbuf; 230# if !defined (linux) 231 if (!stat("/dev/console", &sbuf) && 232 (sbuf.st_uid == getuid()) && 233 !access("/dev/console", R_OK|W_OK)) 234# endif 235#endif 236 { 237#ifdef USE_FILE 238# ifdef linux 239 if (!stat(FILE_NAME, &sbuf)) 240# endif 241 input = fopen (FILE_NAME, "r"); 242#endif 243 244#ifdef USE_PTY 245 if (!input && get_pty (&pty_fd, &tty_fd) == 0) 246 { 247# ifdef TIOCCONS 248 int on = 1; 249 if (ioctl (tty_fd, TIOCCONS, (char *) &on) != -1) 250 input = fdopen (pty_fd, "r"); 251# else 252 int consfd = open("/dev/console", O_RDONLY); 253 if (consfd >= 0) 254 { 255 if (ioctl(consfd, SRIOCSREDIR, tty_fd) != -1) 256 input = fdopen (pty_fd, "r"); 257 close(consfd); 258 } 259# endif 260 } 261#endif /* USE_PTY */ 262 } 263#ifdef USE_OSM 264 /* Don't have to be owner of /dev/console when using /dev/osm. */ 265 if (!input) 266 input = osm_pipe(); 267#endif 268 if (input && app_resources.verbose) 269 { 270 char *hostname; 271 TextAppend (text, "Console log for ", 16); 272 hostname = mit_console_name + MIT_CONSOLE_LEN; 273 TextAppend (text, hostname, strlen (hostname)); 274 TextAppend (text, "\n", 1); 275 } 276 } 277 else 278 { 279 regularFile = FALSE; 280 if (access(app_resources.file, R_OK) == 0) 281 { 282 int fd = open (app_resources.file, 283 O_RDONLY | O_NONBLOCK | O_NOCTTY); 284 if (fd != -1) { 285 input = fdopen (fd, "r"); 286 287 if (input) { 288 struct stat sbuf; 289 290 if ((fstat(fd, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) 291 regularFile = TRUE; 292 } 293 else 294 close(fd); 295 } 296 } 297 } 298 if (!input) 299 { 300 if (app_resources.exitOnFail) 301 exit(0); 302 TextAppend (text, "Couldn't open ", 14); 303 TextAppend (text, app_resources.file, strlen (app_resources.file)); 304 TextAppend (text, "\n", 1); 305 } 306 } 307 else 308 input = stdin; 309 310 if (input) 311 { 312 input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask, 313 inputReady, (XtPointer) text); 314 } 315} 316 317static void 318CloseConsole (void) 319{ 320 if (input) 321 { 322 XtRemoveInput (input_id); 323 fclose (input); 324 } 325#ifdef USE_PTY 326 close (tty_fd); 327#endif 328} 329 330#ifdef USE_OSM 331static void 332KillChild(int sig) 333{ 334 if (child_pid > 0) 335 kill(child_pid, SIGTERM); 336 _exit(0); 337} 338#endif 339 340/*ARGSUSED*/ 341static void _X_NORETURN 342Quit(Widget widget, XEvent *event, String *params, Cardinal *num_params) 343{ 344#ifdef USE_OSM 345 if (child_pid > 0) 346 kill(child_pid, SIGTERM); 347#endif 348 exit (0); 349} 350 351#ifdef USE_OSM 352static int (*ioerror)(Display *); 353 354static int 355IOError(Display *dpy) 356{ 357 if (child_pid > 0) 358 kill(child_pid, SIGTERM); 359 return (*ioerror)(dpy); 360} 361#endif 362 363static void 364Notify(void) 365{ 366 Arg arglist[1]; 367 char *oldName; 368 char *newName; 369 370 if (!iconified || !app_resources.notify || notified) 371 return; 372 XtSetArg (arglist[0], XtNiconName, &oldName); 373 XtGetValues (top, arglist, 1); 374 newName = malloc (strlen (oldName) + 3); 375 if (!newName) 376 return; 377 sprintf (newName, "%s *", oldName); 378 XtSetArg (arglist[0], XtNiconName, newName); 379 XtSetValues (top, arglist, 1); 380 free (newName); 381 notified = True; 382} 383 384/*ARGSUSED*/ 385static void 386Deiconified(Widget widget, XEvent *event, String *params, Cardinal *num_params) 387{ 388 Arg arglist[1]; 389 char *oldName; 390 char *newName; 391 size_t oldlen; 392 393 iconified = False; 394 if (!app_resources.notify || !notified) 395 return; 396 XtSetArg (arglist[0], XtNiconName, &oldName); 397 XtGetValues (top, arglist, 1); 398 oldlen = strlen (oldName); 399 if (oldlen >= 2) 400 { 401 newName = malloc (oldlen - 1); 402 if (!newName) 403 return; 404 strncpy (newName, oldName, oldlen - 2); 405 newName[oldlen - 2] = '\0'; 406 XtSetArg (arglist[0], XtNiconName, newName); 407 XtSetValues (top, arglist, 1); 408 free (newName); 409 } 410 notified = False; 411} 412 413/*ARGSUSED*/ 414static void 415Iconified(Widget widget, XEvent *event, String *params, Cardinal *num_params) 416{ 417 iconified = True; 418} 419 420/*ARGSUSED*/ 421static void 422Clear(Widget widget, XEvent *event, String *params, Cardinal *num_params) 423{ 424 long last; 425 XawTextBlock block; 426 427 last = TextLength (text); 428 block.ptr = ""; 429 block.firstPos = 0; 430 block.length = 0; 431 block.format = FMT8BIT; 432 TextReplace (text, 0, last, &block); 433} 434 435static XtActionsRec actions[] = { 436 { "Quit", Quit }, 437 { "Iconified", Iconified }, 438 { "Deiconified", Deiconified }, 439 { "Clear", Clear }, 440}; 441 442static void 443stripNonprint(char *b) 444{ 445 char *c; 446 447 c = b; 448 while (*b) 449 { 450 if (isprint (*b) || (isspace (*b) && *b != '\r')) 451 { 452 if (c != b) 453 *c = *b; 454 ++c; 455 } 456 ++b; 457 } 458 *c = '\0'; 459} 460 461static void 462inputReady(XtPointer w, int *source, XtInputId *id) 463{ 464 char buffer[1025]; 465 int n; 466 467 n = read (*source, buffer, sizeof (buffer) - 1); 468 if (n <= 0) 469 { 470 if (app_resources.file && regularFile && n == 0) 471 { 472 if (XPending(XtDisplay(w))) 473 return; 474 475 sleep(1); 476 return; 477 } 478 479 fclose (input); 480 XtRemoveInput (*id); 481 482 /* try to reopen if pipe; this can be caused by syslog restart */ 483 if (app_resources.file && !regularFile && n == 0) 484 { 485 OpenConsole(); 486 } 487 } else { 488 Notify(); 489 buffer[n] = '\0'; 490 if (app_resources.stripNonprint) 491 { 492 stripNonprint (buffer); 493 n = strlen (buffer); 494 } 495 496 TextAppend ((Widget) text, buffer, n); 497 } 498} 499 500static Boolean 501ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 502 XtPointer *value, unsigned long *length, int *format) 503{ 504 Display* d = XtDisplay(w); 505 XSelectionRequestEvent* req = 506 XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); 507 508 if (*target == XA_TARGETS(d)) 509 { 510 Atom* targetP; 511 Atom* std_targets; 512 unsigned long std_length; 513 XmuConvertStandardSelection(w, req->time, selection, target, type, 514 (XPointer *)&std_targets, &std_length, 515 format); 516 *value = (XtPointer)XtMalloc(sizeof(Atom)*(std_length + 5)); 517 targetP = *(Atom**)value; 518 *targetP++ = XA_STRING; 519 *targetP++ = XA_TEXT(d); 520 *targetP++ = XA_LENGTH(d); 521 *targetP++ = XA_LIST_LENGTH(d); 522 *targetP++ = XA_CHARACTER_POSITION(d); 523 *length = std_length + (targetP - (*(Atom **) value)); 524 memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); 525 XtFree((char*)std_targets); 526 *type = XA_ATOM; 527 *format = 32; 528 return True; 529 } 530 531 if (*target == XA_LIST_LENGTH(d) || 532 *target == XA_LENGTH(d)) 533 { 534 long * temp; 535 536 temp = (long *) XtMalloc(sizeof(long)); 537 if (*target == XA_LIST_LENGTH(d)) 538 *temp = 1L; 539 else /* *target == XA_LENGTH(d) */ 540 *temp = (long) TextLength (text); 541 542 *value = (XtPointer) temp; 543 *type = XA_INTEGER; 544 *length = 1L; 545 *format = 32; 546 return True; 547 } 548 549 if (*target == XA_CHARACTER_POSITION(d)) 550 { 551 long * temp; 552 553 temp = (long *) XtMalloc(2 * sizeof(long)); 554 temp[0] = (long) 0; 555 temp[1] = TextLength (text); 556 *value = (XtPointer) temp; 557 *type = XA_SPAN(d); 558 *length = 2L; 559 *format = 32; 560 return True; 561 } 562 563 if (*target == XA_STRING || 564 *target == XA_TEXT(d) || 565 *target == XA_COMPOUND_TEXT(d)) 566 { 567 if (*target == XA_COMPOUND_TEXT(d)) 568 *type = *target; 569 else 570 *type = XA_STRING; 571 *length = TextLength (text); 572 *value = (XtPointer)_XawTextGetSTRING((TextWidget) text, 0, *length); 573 *format = 8; 574 /* 575 * Drop our connection to the file; the new console program 576 * will open as soon as it receives the selection contents; there 577 * is a small window where console output will not be redirected, 578 * but I see no way of avoiding that without having two programs 579 * attempt to redirect console output at the same time, which seems 580 * worse 581 */ 582 CloseConsole (); 583 return True; 584 } 585 586 if (XmuConvertStandardSelection(w, req->time, selection, target, type, 587 (XPointer *)value, length, format)) 588 return True; 589 590 return False; 591} 592 593static void _X_NORETURN 594LoseSelection(Widget w, Atom *selection) 595{ 596 Quit (w, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL); 597} 598 599/*ARGSUSED*/ 600static void 601InsertSelection(Widget w, XtPointer client_data, Atom *selection, Atom *type, 602 XtPointer value, unsigned long *length, int *format) 603{ 604 if (*type != XT_CONVERT_FAIL) 605 TextInsert (text, (char *) value, *length); 606 XtOwnSelection(top, mit_console, CurrentTime, 607 ConvertSelection, LoseSelection, NULL); 608 OpenConsole (); 609} 610 611int 612main(int argc, char *argv[]) 613{ 614 Arg arglist[10]; 615 Cardinal num_args; 616 617 XtSetLanguageProc(NULL,NULL,NULL); 618 top = XtInitialize ("xconsole", "XConsole", options, XtNumber (options), 619 &argc, argv); 620 XtGetApplicationResources (top, (XtPointer)&app_resources, resources, 621 XtNumber (resources), NULL, 0); 622 623 if (app_resources.daemon) 624 if (fork ()) exit (0); 625 XtAddActions (actions, XtNumber (actions)); 626 627 text = XtCreateManagedWidget ("text", asciiTextWidgetClass, 628 top, NULL, 0); 629 630 XtRealizeWidget (top); 631 num_args = 0; 632 XtSetArg(arglist[num_args], XtNiconic, &iconified); num_args++; 633 XtGetValues(top, arglist, num_args); 634 if (iconified) 635 Iconified((Widget)NULL, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL); 636 else 637 Deiconified((Widget)NULL,(XEvent*)NULL,(String*)NULL,(Cardinal*)NULL); 638 wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", 639 False); 640 (void) XSetWMProtocols (XtDisplay(top), XtWindow(top), 641 &wm_delete_window, 1); 642 643 XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255); 644 645 mit_console = XInternAtom(XtDisplay(top), mit_console_name, False); 646 647 if (XGetSelectionOwner (XtDisplay (top), mit_console)) 648 { 649 XtGetSelectionValue(top, mit_console, XA_STRING, InsertSelection, 650 NULL, CurrentTime); 651 } 652 else 653 { 654 XtOwnSelection(top, mit_console, CurrentTime, 655 ConvertSelection, LoseSelection, NULL); 656 OpenConsole (); 657 } 658#ifdef USE_OSM 659 ioerror = XSetIOErrorHandler(IOError); 660#endif 661 XtMainLoop (); 662 return 0; 663} 664 665static long 666TextLength(Widget w) 667{ 668 return XawTextSourceScan (XawTextGetSource (w), 669 (XawTextPosition) 0, 670 XawstAll, XawsdRight, 1, TRUE); 671} 672 673static void 674TextReplace(Widget w, int start, int end, XawTextBlock *block) 675{ 676 Arg arg; 677 Widget source; 678 XawTextEditType edit_mode; 679 680 source = XawTextGetSource (w); 681 XtSetArg (arg, XtNeditType, &edit_mode); 682 XtGetValues (source, &arg, ONE); 683 XtSetArg (arg, XtNeditType, XawtextEdit); 684 XtSetValues (source, &arg, ONE); 685 XawTextReplace (w, start, end, block); 686 XtSetArg (arg, XtNeditType, edit_mode); 687 XtSetValues (source, &arg, ONE); 688} 689 690static void 691TextAppend(Widget w, char *s, int len) 692{ 693 long last, current; 694 XawTextBlock block; 695 696 current = XawTextGetInsertionPoint (w); 697 last = TextLength (w); 698 block.ptr = s; 699 block.firstPos = 0; 700 block.length = len; 701 block.format = FMT8BIT; 702 /* 703 * If saveLines is 1, just replace the entire contents of the widget 704 * each time, so the test in ExceededMaxLines() isn't fooled. 705 */ 706 if (app_resources.saveLines == 1) 707 TextReplace (w, 0, last, &block); 708 else 709 TextReplace (w, last, last, &block); 710 if (current == last) 711 XawTextSetInsertionPoint (w, last + block.length); 712 if (ExceededMaxLines(w)) 713 ScrollLine(w); 714} 715 716static void 717TextInsert(Widget w, char *s, int len) 718{ 719 XawTextBlock block; 720 long current; 721 722 current = XawTextGetInsertionPoint (w); 723 block.ptr = s; 724 block.firstPos = 0; 725 block.length = len; 726 block.format = FMT8BIT; 727 TextReplace (w, 0, 0, &block); 728 if (current == 0) 729 XawTextSetInsertionPoint (w, len); 730 if (ExceededMaxLines(w)) 731 ScrollLine(w); 732} 733 734static Bool 735ExceededMaxLines(Widget w) 736{ 737 XawTextPosition end_of_last_line; 738 Bool retval = False; 739 740 if (app_resources.saveLines > 0) 741 { 742 /* 743 * XawTextSourceScan() will return the end of the widget if it cannot 744 * find what it is searching for. 745 */ 746 end_of_last_line = XawTextSourceScan (XawTextGetSource (w), 747 (XawTextPosition) 0, 748 XawstEOL, XawsdRight, 749 app_resources.saveLines, TRUE); 750 if (TextLength(w) > end_of_last_line) 751 retval = True; 752 else 753 retval = False; 754 } 755 else 756 retval = False; 757 return retval; 758} 759 760static void 761ScrollLine(Widget w) 762{ 763 XawTextPosition firstnewline; 764 XawTextBlock block; 765 766 /* 767 * This is pretty inefficient but should work well enough unless the 768 * console device is getting totally spammed. Generally, new lines 769 * only come in one at a time anyway. 770 */ 771 firstnewline = XawTextSourceScan (XawTextGetSource (w), 772 (XawTextPosition) 0, 773 XawstEOL, XawsdRight, 1, TRUE); 774 block.ptr = ""; 775 block.firstPos = 0; 776 block.length = 0; 777 block.format = FMT8BIT; 778 TextReplace (w, 0, firstnewline, &block); 779} 780 781#ifdef USE_PTY 782/* 783 * This function opens up a pty master and stuffs its value into pty. 784 * If it finds one, it returns a value of 0. If it does not find one, 785 * it returns a value of !0. This routine is designed to be re-entrant, 786 * so that if a pty master is found and later, we find that the slave 787 * has problems, we can re-enter this function and get another one. 788 */ 789 790static int 791get_pty(int *pty, int *tty) 792{ 793#ifdef HAS_OPENPTY 794 if (openpty(pty, tty, NULL, NULL, NULL) == -1) { 795 return 1; 796 } 797 return 0; 798#else 799 static char ttydev[64], ptydev[64]; 800 801#if defined (SVR4) || defined (USE_PTS) 802#if defined (_AIX) 803 if ((*pty = open ("/dev/ptc", O_RDWR)) < 0) 804#else 805 if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) 806#endif 807 return 1; 808 grantpt(*pty); 809 unlockpt(*pty); 810 strcpy(ttydev, (char *)ptsname(*pty)); 811 if ((*tty = open(ttydev, O_RDWR)) >= 0) 812 { 813 (void)ioctl(*tty, I_PUSH, "ttcompat"); 814 return 0; 815 } 816 if (*pty >= 0) 817 close (*pty); 818#else /* !SVR4, need lots of code */ 819#ifdef USE_GET_PSEUDOTTY 820 if ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 && 821 (*tty = open (ttydev, O_RDWR)) >= 0) 822 return 0; 823 if (*pty >= 0) 824 close (*pty); 825#else 826 static int devindex, letter = 0; 827 828 strcpy (ttydev, "/dev/ttyxx"); 829 strcpy (ptydev, "/dev/ptyxx"); 830 while (PTYCHAR1[letter]) { 831 ttydev [strlen(ttydev) - 2] = ptydev [strlen(ptydev) - 2] = 832 PTYCHAR1 [letter]; 833 834 while (PTYCHAR2[devindex]) { 835 ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] = 836 PTYCHAR2 [devindex]; 837 if ((*pty = open (ptydev, O_RDWR)) >= 0 && 838 (*tty = open (ttydev, O_RDWR)) >= 0) 839 { 840 /* 841 * We need to set things up for our next entry 842 * into this function! 843 */ 844 (void) devindex++; 845 return(0); 846 } 847 if (*pty >= 0) 848 close (*pty); 849 devindex++; 850 } 851 devindex = 0; 852 (void) letter++; 853 } 854#endif /* USE_GET_PSEUDOTTY */ 855#endif /* SVR4 */ 856 /* 857 * We were unable to allocate a pty master! Return an error 858 * condition and let our caller terminate cleanly. 859 */ 860 return(1); 861#endif /* HAS_OPENPTY */ 862} 863#endif 864 865#ifdef USE_OSM 866/* 867 * On SYSV386 there is a special device, /dev/osm, where system messages 868 * are sent. Problem is that we can't perform a select(2) on this device. 869 * So this routine creates a streams-pty where one end reads the device and 870 * sends the output to xconsole. 871 */ 872 873#ifdef SCO325 874#define OSM_DEVICE "/dev/error" 875#else 876#ifdef __UNIXWARE__ 877#define OSM_DEVICE "/dev/osm2" 878#define NO_READAHEAD 879#else 880#define OSM_DEVICE "/dev/osm" 881#endif 882#endif 883 884static FILE * 885osm_pipe(void) 886{ 887 int tty; 888 char ttydev[64]; 889 890 if (access(OSM_DEVICE, R_OK) < 0) 891 return NULL; 892#if defined (_AIX) 893 if ((tty = open("/dev/ptc", O_RDWR)) < 0) 894#else 895 if ((tty = open("/dev/ptmx", O_RDWR)) < 0) 896#endif 897 return NULL; 898 899 grantpt(tty); 900 unlockpt(tty); 901 strcpy(ttydev, (char *)ptsname(tty)); 902 903 if ((child_pid = fork()) == 0) 904 { 905 int pty, osm, nbytes, skip; 906 char cbuf[128]; 907 908 skip = 0; 909#ifndef NO_READAHEAD 910 osm = open(OSM_DEVICE, O_RDONLY); 911 if (osm >= 0) 912 { 913 while ((nbytes = read(osm, cbuf, sizeof(cbuf))) > 0) 914 skip += nbytes; 915 close(osm); 916 } 917#endif 918 pty = open(ttydev, O_RDWR); 919 if (pty < 0) 920 exit(1); 921 osm = open(OSM_DEVICE, O_RDONLY); 922 if (osm < 0) 923 exit(1); 924 for (nbytes = 0; skip > 0 && nbytes >= 0; skip -= nbytes) 925 { 926 nbytes = skip; 927 if (nbytes > sizeof(cbuf)) 928 nbytes = sizeof(cbuf); 929 nbytes = read(osm, cbuf, nbytes); 930 } 931 while ((nbytes = read(osm, cbuf, sizeof(cbuf))) >= 0) 932 write(pty, cbuf, nbytes); 933 exit(0); 934 } 935 signal(SIGHUP, KillChild); 936 signal(SIGINT, KillChild); 937 signal(SIGTERM, KillChild); 938 return fdopen(tty, "r"); 939} 940#endif /* USE_OSM */ 941