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