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