xconsole.c revision eaad2c89
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; 181static char ttydev[64], ptydev[64]; 182# endif 183#endif 184 185#if (defined(SVR4) && !defined(sun)) || (defined(SYSV) && defined(i386)) 186#define USE_OSM 187#include <signal.h> 188#endif 189 190#ifdef USE_PTY 191static int get_pty(int *pty, int *tty, char *ttydev, char *ptydev); 192#endif 193 194#ifdef USE_OSM 195static FILE *osm_pipe(void); 196static int child_pid; 197#endif 198 199/* Copied from xterm/ptyx.h */ 200#ifndef PTYCHAR1 201#ifdef __hpux 202#define PTYCHAR1 "zyxwvutsrqp" 203#else /* !__hpux */ 204#define PTYCHAR1 "pqrstuvwxyzPQRSTUVWXYZ" 205#endif /* !__hpux */ 206#endif /* !PTYCHAR1 */ 207 208#ifndef PTYCHAR2 209#ifdef __hpux 210#define PTYCHAR2 "fedcba9876543210" 211#else /* !__hpux */ 212#ifdef __FreeBSD__ 213#define PTYCHAR2 "0123456789abcdefghijklmnopqrstuv" 214#else /* !__FreeBSD__ */ 215#define PTYCHAR2 "0123456789abcdef" 216#endif /* !__FreeBSD__ */ 217#endif /* !__hpux */ 218#endif /* !PTYCHAR2 */ 219 220static void 221OpenConsole(void) 222{ 223 input = 0; 224 if (app_resources.file) 225 { 226 if (!strcmp (app_resources.file, "console")) 227 { 228 /* must be owner and have read/write permission */ 229#if !defined(__NetBSD__) && !defined(__OpenBSD__) 230 struct stat sbuf; 231# if !defined (linux) 232 if (!stat("/dev/console", &sbuf) && 233 (sbuf.st_uid == getuid()) && 234 !access("/dev/console", R_OK|W_OK)) 235# endif 236#endif 237 { 238#ifdef USE_FILE 239# ifdef linux 240 if (!stat(FILE_NAME, &sbuf)) 241# endif 242 input = fopen (FILE_NAME, "r"); 243#endif 244 245#ifdef USE_PTY 246 if (!input && get_pty (&pty_fd, &tty_fd, ttydev, ptydev) == 0) 247 { 248# ifdef TIOCCONS 249 int on = 1; 250 if (ioctl (tty_fd, TIOCCONS, (char *) &on) != -1) 251 input = fdopen (pty_fd, "r"); 252# else 253 int consfd = open("/dev/console", O_RDONLY); 254 if (consfd >= 0) 255 { 256 if (ioctl(consfd, SRIOCSREDIR, tty_fd) != -1) 257 input = fdopen (pty_fd, "r"); 258 close(consfd); 259 } 260# endif 261 } 262#endif /* USE_PTY */ 263 } 264#ifdef USE_OSM 265 /* Don't have to be owner of /dev/console when using /dev/osm. */ 266 if (!input) 267 input = osm_pipe(); 268#endif 269 if (input && app_resources.verbose) 270 { 271 char *hostname; 272 TextAppend (text, "Console log for ", 16); 273 hostname = mit_console_name + MIT_CONSOLE_LEN; 274 TextAppend (text, hostname, strlen (hostname)); 275 TextAppend (text, "\n", 1); 276 } 277 } 278 else 279 { 280 regularFile = FALSE; 281 if (access(app_resources.file, R_OK) == 0) 282 { 283 int fd = open (app_resources.file, 284 O_RDONLY | O_NONBLOCK | O_NOCTTY); 285 if (fd != -1) { 286 input = fdopen (fd, "r"); 287 288 if (input) { 289 struct stat sbuf; 290 291 if ((fstat(fd, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) 292 regularFile = TRUE; 293 } 294 else 295 close(fd); 296 } 297 } 298 } 299 if (!input) 300 { 301 if (app_resources.exitOnFail) 302 exit(0); 303 TextAppend (text, "Couldn't open ", 14); 304 TextAppend (text, app_resources.file, strlen (app_resources.file)); 305 TextAppend (text, "\n", 1); 306 } 307 } 308 else 309 input = stdin; 310 311 if (input) 312 { 313 input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask, 314 inputReady, (XtPointer) text); 315 } 316} 317 318static void 319CloseConsole (void) 320{ 321 if (input) 322 { 323 XtRemoveInput (input_id); 324 fclose (input); 325 } 326#ifdef USE_PTY 327 close (tty_fd); 328#endif 329} 330 331#ifdef USE_OSM 332static void 333KillChild(int sig) 334{ 335 if (child_pid > 0) 336 kill(child_pid, SIGTERM); 337 _exit(0); 338} 339#endif 340 341/*ARGSUSED*/ 342static void _X_NORETURN 343Quit(Widget widget, XEvent *event, String *params, Cardinal *num_params) 344{ 345#ifdef USE_OSM 346 if (child_pid > 0) 347 kill(child_pid, SIGTERM); 348#endif 349 exit (0); 350} 351 352#ifdef USE_OSM 353static int (*ioerror)(Display *); 354 355static int 356IOError(Display *dpy) 357{ 358 if (child_pid > 0) 359 kill(child_pid, SIGTERM); 360 return (*ioerror)(dpy); 361} 362#endif 363 364static void 365Notify(void) 366{ 367 Arg arglist[1]; 368 char *oldName; 369 char *newName; 370 371 if (!iconified || !app_resources.notify || notified) 372 return; 373 XtSetArg (arglist[0], XtNiconName, &oldName); 374 XtGetValues (top, arglist, 1); 375 newName = malloc (strlen (oldName) + 3); 376 if (!newName) 377 return; 378 sprintf (newName, "%s *", oldName); 379 XtSetArg (arglist[0], XtNiconName, newName); 380 XtSetValues (top, arglist, 1); 381 free (newName); 382 notified = True; 383} 384 385/*ARGSUSED*/ 386static void 387Deiconified(Widget widget, XEvent *event, String *params, Cardinal *num_params) 388{ 389 Arg arglist[1]; 390 char *oldName; 391 char *newName; 392 size_t oldlen; 393 394 iconified = False; 395 if (!app_resources.notify || !notified) 396 return; 397 XtSetArg (arglist[0], XtNiconName, &oldName); 398 XtGetValues (top, arglist, 1); 399 oldlen = strlen (oldName); 400 if (oldlen >= 2) 401 { 402 newName = malloc (oldlen - 1); 403 if (!newName) 404 return; 405 strncpy (newName, oldName, oldlen - 2); 406 newName[oldlen - 2] = '\0'; 407 XtSetArg (arglist[0], XtNiconName, newName); 408 XtSetValues (top, arglist, 1); 409 free (newName); 410 } 411 notified = False; 412} 413 414/*ARGSUSED*/ 415static void 416Iconified(Widget widget, XEvent *event, String *params, Cardinal *num_params) 417{ 418 iconified = True; 419} 420 421/*ARGSUSED*/ 422static void 423Clear(Widget widget, XEvent *event, String *params, Cardinal *num_params) 424{ 425 long last; 426 XawTextBlock block; 427 428 last = TextLength (text); 429 block.ptr = ""; 430 block.firstPos = 0; 431 block.length = 0; 432 block.format = FMT8BIT; 433 TextReplace (text, 0, last, &block); 434} 435 436static XtActionsRec actions[] = { 437 { "Quit", Quit }, 438 { "Iconified", Iconified }, 439 { "Deiconified", Deiconified }, 440 { "Clear", Clear }, 441}; 442 443static void 444stripNonprint(char *b) 445{ 446 char *c; 447 448 c = b; 449 while (*b) 450 { 451 if (isprint (*b) || (isspace (*b) && *b != '\r')) 452 { 453 if (c != b) 454 *c = *b; 455 ++c; 456 } 457 ++b; 458 } 459 *c = '\0'; 460} 461 462static void 463inputReady(XtPointer w, int *source, XtInputId *id) 464{ 465 char buffer[1025]; 466 int n; 467 468 n = read (*source, buffer, sizeof (buffer) - 1); 469 if (n <= 0) 470 { 471 if (app_resources.file && regularFile && n == 0) 472 { 473 if (XPending(XtDisplay(w))) 474 return; 475 476 sleep(1); 477 return; 478 } 479 480 fclose (input); 481 XtRemoveInput (*id); 482 483 /* try to reopen if pipe; this can be caused by syslog restart */ 484 if (app_resources.file && !regularFile && n == 0) 485 { 486 OpenConsole(); 487 } 488 } else { 489 Notify(); 490 buffer[n] = '\0'; 491 if (app_resources.stripNonprint) 492 { 493 stripNonprint (buffer); 494 n = strlen (buffer); 495 } 496 497 TextAppend ((Widget) text, buffer, n); 498 } 499} 500 501static Boolean 502ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type, 503 XtPointer *value, unsigned long *length, int *format) 504{ 505 Display* d = XtDisplay(w); 506 XSelectionRequestEvent* req = 507 XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); 508 509 if (*target == XA_TARGETS(d)) 510 { 511 Atom* targetP; 512 Atom* std_targets; 513 unsigned long std_length; 514 XmuConvertStandardSelection(w, req->time, selection, target, type, 515 (XPointer *)&std_targets, &std_length, 516 format); 517 *value = (XtPointer)XtMalloc(sizeof(Atom)*(std_length + 5)); 518 targetP = *(Atom**)value; 519 *targetP++ = XA_STRING; 520 *targetP++ = XA_TEXT(d); 521 *targetP++ = XA_LENGTH(d); 522 *targetP++ = XA_LIST_LENGTH(d); 523 *targetP++ = XA_CHARACTER_POSITION(d); 524 *length = std_length + (targetP - (*(Atom **) value)); 525 memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); 526 XtFree((char*)std_targets); 527 *type = XA_ATOM; 528 *format = 32; 529 return True; 530 } 531 532 if (*target == XA_LIST_LENGTH(d) || 533 *target == XA_LENGTH(d)) 534 { 535 long * temp; 536 537 temp = (long *) XtMalloc(sizeof(long)); 538 if (*target == XA_LIST_LENGTH(d)) 539 *temp = 1L; 540 else /* *target == XA_LENGTH(d) */ 541 *temp = (long) TextLength (text); 542 543 *value = (XtPointer) temp; 544 *type = XA_INTEGER; 545 *length = 1L; 546 *format = 32; 547 return True; 548 } 549 550 if (*target == XA_CHARACTER_POSITION(d)) 551 { 552 long * temp; 553 554 temp = (long *) XtMalloc(2 * sizeof(long)); 555 temp[0] = (long) 0; 556 temp[1] = TextLength (text); 557 *value = (XtPointer) temp; 558 *type = XA_SPAN(d); 559 *length = 2L; 560 *format = 32; 561 return True; 562 } 563 564 if (*target == XA_STRING || 565 *target == XA_TEXT(d) || 566 *target == XA_COMPOUND_TEXT(d)) 567 { 568 if (*target == XA_COMPOUND_TEXT(d)) 569 *type = *target; 570 else 571 *type = XA_STRING; 572 *length = TextLength (text); 573 *value = (XtPointer)_XawTextGetSTRING((TextWidget) text, 0, *length); 574 *format = 8; 575 /* 576 * Drop our connection to the file; the new console program 577 * will open as soon as it receives the selection contents; there 578 * is a small window where console output will not be redirected, 579 * but I see no way of avoiding that without having two programs 580 * attempt to redirect console output at the same time, which seems 581 * worse 582 */ 583 CloseConsole (); 584 return True; 585 } 586 587 if (XmuConvertStandardSelection(w, req->time, selection, target, type, 588 (XPointer *)value, length, format)) 589 return True; 590 591 return False; 592} 593 594static void _X_NORETURN 595LoseSelection(Widget w, Atom *selection) 596{ 597 Quit (w, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL); 598} 599 600/*ARGSUSED*/ 601static void 602InsertSelection(Widget w, XtPointer client_data, Atom *selection, Atom *type, 603 XtPointer value, unsigned long *length, int *format) 604{ 605 if (*type != XT_CONVERT_FAIL) 606 TextInsert (text, (char *) value, *length); 607 XtOwnSelection(top, mit_console, CurrentTime, 608 ConvertSelection, LoseSelection, NULL); 609 OpenConsole (); 610} 611 612int 613main(int argc, char *argv[]) 614{ 615 Arg arglist[10]; 616 Cardinal num_args; 617 618 XtSetLanguageProc(NULL,NULL,NULL); 619 top = XtInitialize ("xconsole", "XConsole", options, XtNumber (options), 620 &argc, argv); 621 XtGetApplicationResources (top, (XtPointer)&app_resources, resources, 622 XtNumber (resources), NULL, 0); 623 624 if (app_resources.daemon) 625 if (fork ()) exit (0); 626 XtAddActions (actions, XtNumber (actions)); 627 628 text = XtCreateManagedWidget ("text", asciiTextWidgetClass, 629 top, NULL, 0); 630 631 XtRealizeWidget (top); 632 num_args = 0; 633 XtSetArg(arglist[num_args], XtNiconic, &iconified); num_args++; 634 XtGetValues(top, arglist, num_args); 635 if (iconified) 636 Iconified((Widget)NULL, (XEvent*)NULL, (String*)NULL, (Cardinal*)NULL); 637 else 638 Deiconified((Widget)NULL,(XEvent*)NULL,(String*)NULL,(Cardinal*)NULL); 639 wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", 640 False); 641 (void) XSetWMProtocols (XtDisplay(top), XtWindow(top), 642 &wm_delete_window, 1); 643 644 XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255); 645 646 mit_console = XInternAtom(XtDisplay(top), mit_console_name, False); 647 648 if (XGetSelectionOwner (XtDisplay (top), mit_console)) 649 { 650 XtGetSelectionValue(top, mit_console, XA_STRING, InsertSelection, 651 NULL, CurrentTime); 652 } 653 else 654 { 655 XtOwnSelection(top, mit_console, CurrentTime, 656 ConvertSelection, LoseSelection, NULL); 657 OpenConsole (); 658 } 659#ifdef USE_OSM 660 ioerror = XSetIOErrorHandler(IOError); 661#endif 662 XtMainLoop (); 663 return 0; 664} 665 666static long 667TextLength(Widget w) 668{ 669 return XawTextSourceScan (XawTextGetSource (w), 670 (XawTextPosition) 0, 671 XawstAll, XawsdRight, 1, TRUE); 672} 673 674static void 675TextReplace(Widget w, int start, int end, XawTextBlock *block) 676{ 677 Arg arg; 678 Widget source; 679 XawTextEditType edit_mode; 680 681 source = XawTextGetSource (w); 682 XtSetArg (arg, XtNeditType, &edit_mode); 683 XtGetValues (source, &arg, ONE); 684 XtSetArg (arg, XtNeditType, XawtextEdit); 685 XtSetValues (source, &arg, ONE); 686 XawTextReplace (w, start, end, block); 687 XtSetArg (arg, XtNeditType, edit_mode); 688 XtSetValues (source, &arg, ONE); 689} 690 691static void 692TextAppend(Widget w, char *s, int len) 693{ 694 long last, current; 695 XawTextBlock block; 696 697 current = XawTextGetInsertionPoint (w); 698 last = TextLength (w); 699 block.ptr = s; 700 block.firstPos = 0; 701 block.length = len; 702 block.format = FMT8BIT; 703 /* 704 * If saveLines is 1, just replace the entire contents of the widget 705 * each time, so the test in ExceededMaxLines() isn't fooled. 706 */ 707 if (app_resources.saveLines == 1) 708 TextReplace (w, 0, last, &block); 709 else 710 TextReplace (w, last, last, &block); 711 if (current == last) 712 XawTextSetInsertionPoint (w, last + block.length); 713 if (ExceededMaxLines(w)) 714 ScrollLine(w); 715} 716 717static void 718TextInsert(Widget w, char *s, int len) 719{ 720 XawTextBlock block; 721 long current; 722 723 current = XawTextGetInsertionPoint (w); 724 block.ptr = s; 725 block.firstPos = 0; 726 block.length = len; 727 block.format = FMT8BIT; 728 TextReplace (w, 0, 0, &block); 729 if (current == 0) 730 XawTextSetInsertionPoint (w, len); 731 if (ExceededMaxLines(w)) 732 ScrollLine(w); 733} 734 735static Bool 736ExceededMaxLines(Widget w) 737{ 738 XawTextPosition end_of_last_line; 739 Bool retval = False; 740 741 if (app_resources.saveLines > 0) 742 { 743 /* 744 * XawTextSourceScan() will return the end of the widget if it cannot 745 * find what it is searching for. 746 */ 747 end_of_last_line = XawTextSourceScan (XawTextGetSource (w), 748 (XawTextPosition) 0, 749 XawstEOL, XawsdRight, 750 app_resources.saveLines, TRUE); 751 if (TextLength(w) > end_of_last_line) 752 retval = True; 753 else 754 retval = False; 755 } 756 else 757 retval = False; 758 return retval; 759} 760 761static void 762ScrollLine(Widget w) 763{ 764 XawTextPosition firstnewline; 765 XawTextBlock block; 766 767 /* 768 * This is pretty inefficient but should work well enough unless the 769 * console device is getting totally spammed. Generally, new lines 770 * only come in one at a time anyway. 771 */ 772 firstnewline = XawTextSourceScan (XawTextGetSource (w), 773 (XawTextPosition) 0, 774 XawstEOL, XawsdRight, 1, TRUE); 775 block.ptr = ""; 776 block.firstPos = 0; 777 block.length = 0; 778 block.format = FMT8BIT; 779 TextReplace (w, 0, firstnewline, &block); 780} 781 782#ifdef USE_PTY 783/* 784 * This function opens up a pty master and stuffs its value into pty. 785 * If it finds one, it returns a value of 0. If it does not find one, 786 * it returns a value of !0. This routine is designed to be re-entrant, 787 * so that if a pty master is found and later, we find that the slave 788 * has problems, we can re-enter this function and get another one. 789 */ 790 791static int 792get_pty(int *pty, int *tty, char *ttydev, char *ptydev) 793{ 794#ifdef HAS_OPENPTY 795 if (openpty(pty, tty, NULL, NULL, NULL) == -1) { 796 return 1; 797 } 798 return 0; 799#elif defined (SVR4) || defined (USE_PTS) 800#if defined (_AIX) 801 if ((*pty = open ("/dev/ptc", O_RDWR)) < 0) 802#else 803 if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) 804#endif 805 return 1; 806 grantpt(*pty); 807 unlockpt(*pty); 808 strcpy(ttydev, (char *)ptsname(*pty)); 809 if ((*tty = open(ttydev, O_RDWR)) >= 0) 810 { 811 (void)ioctl(*tty, I_PUSH, "ttcompat"); 812 return 0; 813 } 814 if (*pty >= 0) 815 close (*pty); 816#else /* !SVR4, need lots of code */ 817#ifdef USE_GET_PSEUDOTTY 818 if ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 && 819 (*tty = open (ttydev, O_RDWR)) >= 0) 820 return 0; 821 if (*pty >= 0) 822 close (*pty); 823#else 824 static int devindex, letter = 0; 825 826#ifdef sgi 827 { 828 char *slave; 829 slave = _getpty (pty, O_RDWR, 0622, 0); 830 if ((*tty = open (slave, O_RDWR)) != -1) 831 return 0; 832 } 833#else 834 strcpy (ttydev, "/dev/ttyxx"); 835 strcpy (ptydev, "/dev/ptyxx"); 836 while (PTYCHAR1[letter]) { 837 ttydev [strlen(ttydev) - 2] = ptydev [strlen(ptydev) - 2] = 838 PTYCHAR1 [letter]; 839 840 while (PTYCHAR2[devindex]) { 841 ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] = 842 PTYCHAR2 [devindex]; 843 if ((*pty = open (ptydev, O_RDWR)) >= 0 && 844 (*tty = open (ttydev, O_RDWR)) >= 0) 845 { 846 /* 847 * We need to set things up for our next entry 848 * into this function! 849 */ 850 (void) devindex++; 851 return(0); 852 } 853 if (*pty >= 0) 854 close (*pty); 855 devindex++; 856 } 857 devindex = 0; 858 (void) letter++; 859 } 860#endif /* sgi else not sgi */ 861#endif /* USE_GET_PSEUDOTTY */ 862#endif /* SVR4 */ 863 /* 864 * We were unable to allocate a pty master! Return an error 865 * condition and let our caller terminate cleanly. 866 */ 867 return(1); 868} 869#endif 870 871#ifdef USE_OSM 872/* 873 * On SYSV386 there is a special device, /dev/osm, where system messages 874 * are sent. Problem is that we can't perform a select(2) on this device. 875 * So this routine creates a streams-pty where one end reads the device and 876 * sends the output to xconsole. 877 */ 878 879#ifdef SCO325 880#define OSM_DEVICE "/dev/error" 881#else 882#ifdef __UNIXWARE__ 883#define OSM_DEVICE "/dev/osm2" 884#define NO_READAHEAD 885#else 886#define OSM_DEVICE "/dev/osm" 887#endif 888#endif 889 890static FILE * 891osm_pipe(void) 892{ 893 int tty; 894 char ttydev[64]; 895 896 if (access(OSM_DEVICE, R_OK) < 0) 897 return NULL; 898#if defined (_AIX) 899 if ((tty = open("/dev/ptc", O_RDWR)) < 0) 900#else 901 if ((tty = open("/dev/ptmx", O_RDWR)) < 0) 902#endif 903 return NULL; 904 905 grantpt(tty); 906 unlockpt(tty); 907 strcpy(ttydev, (char *)ptsname(tty)); 908 909 if ((child_pid = fork()) == 0) 910 { 911 int pty, osm, nbytes, skip; 912 char cbuf[128]; 913 914 skip = 0; 915#ifndef NO_READAHEAD 916 osm = open(OSM_DEVICE, O_RDONLY); 917 if (osm >= 0) 918 { 919 while ((nbytes = read(osm, cbuf, sizeof(cbuf))) > 0) 920 skip += nbytes; 921 close(osm); 922 } 923#endif 924 pty = open(ttydev, O_RDWR); 925 if (pty < 0) 926 exit(1); 927 osm = open(OSM_DEVICE, O_RDONLY); 928 if (osm < 0) 929 exit(1); 930 for (nbytes = 0; skip > 0 && nbytes >= 0; skip -= nbytes) 931 { 932 nbytes = skip; 933 if (nbytes > sizeof(cbuf)) 934 nbytes = sizeof(cbuf); 935 nbytes = read(osm, cbuf, nbytes); 936 } 937 while ((nbytes = read(osm, cbuf, sizeof(cbuf))) >= 0) 938 write(pty, cbuf, nbytes); 939 exit(0); 940 } 941 signal(SIGHUP, KillChild); 942 signal(SIGINT, KillChild); 943 signal(SIGTERM, KillChild); 944 return fdopen(tty, "r"); 945} 946#endif /* USE_OSM */ 947