home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xconsole / xconsole.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-25  |  17.4 KB  |  726 lines

  1. /*
  2.  * $XConsortium: xconsole.c,v 1.9 91/07/25 14:23:46 rws Exp $
  3.  *
  4.  * Copyright 1990 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Keith Packard, MIT X Consortium
  24.  */
  25.  
  26. #include <X11/Intrinsic.h>
  27. #include <X11/StringDefs.h>
  28. #include <X11/Xatom.h>
  29.  
  30. #include <X11/Xmu/Atoms.h>
  31. #include <X11/Xmu/StdSel.h>
  32.  
  33. #include <X11/Shell.h>
  34. #include <X11/Xaw/Form.h>
  35. #include <X11/Xaw/Label.h>
  36. #include <X11/Xaw/Command.h>
  37. #include <X11/Xaw/AsciiText.h>
  38. #include <X11/Xaw/Dialog.h>
  39. #include <X11/Xaw/Cardinals.h>
  40. #include <X11/Xaw/Paned.h>
  41. #include <X11/Xaw/Box.h>
  42.  
  43. #include <X11/Xos.h>
  44. #include <X11/Xfuncs.h>
  45. #include <sys/stat.h>
  46. #include <stdio.h>
  47. #include <ctype.h>
  48.  
  49. /* Fix ISC brain damage.  When using gcc fdopen isn't declared in <stdio.h>. */
  50. #if defined(SYSV) && defined(SYSV386) && defined(__STDC__) && defined(ISC)
  51. extern FILE *fdopen(int, char const *);
  52. #endif
  53.  
  54. static long    TextLength ();
  55.  
  56. static Widget    top, text;
  57.  
  58. static XtInputId    input_id;
  59.  
  60. static FILE    *input;
  61.  
  62. static Boolean    notified;
  63. static Boolean    iconified;
  64.  
  65. static Atom    wm_delete_window;
  66. static Atom    mit_console;
  67. #define MIT_CONSOLE_LEN    12
  68. #define MIT_CONSOLE "MIT_CONSOLE_"
  69. static char    mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
  70.  
  71. static struct _app_resources {
  72.     char    *file;
  73.     Boolean stripNonprint;
  74.     Boolean notify;
  75.     Boolean daemon;
  76.     Boolean verbose;
  77.     Boolean exitOnFail;
  78. } app_resources;
  79.  
  80. #define Offset(field) XtOffsetOf(struct _app_resources, field)
  81.  
  82. static XtResource  resources[] = {
  83.     {"file",    "File",        XtRString,    sizeof (char *),
  84.     Offset (file),    XtRString,  "console" },
  85.     {"notify",    "Notify",   XtRBoolean,    sizeof (Boolean),
  86.     Offset (notify), XtRImmediate, (XtPointer)True },
  87.     {"stripNonprint",    "StripNonprint",    XtRBoolean, sizeof (Boolean),
  88.     Offset (stripNonprint), XtRImmediate, (XtPointer)True },
  89.     {"daemon",        "Daemon",        XtRBoolean,    sizeof (Boolean),
  90.     Offset (daemon), XtRImmediate, (XtPointer)False},
  91.     {"verbose",        "Verbose",        XtRBoolean,    sizeof (Boolean),
  92.     Offset (verbose),XtRImmediate, (XtPointer)False},
  93.     {"exitOnFail",    "ExitOnFail",    XtRBoolean,    sizeof (Boolean),
  94.     Offset (exitOnFail),XtRImmediate, (XtPointer)False},
  95. };
  96.  
  97. #undef Offset
  98.  
  99. static XrmOptionDescRec options[] = {
  100.     {"-file",        "*file",        XrmoptionSepArg,    NULL},
  101.     {"-notify",        "*notify",        XrmoptionNoArg,        "TRUE"},
  102.     {"-nonotify",   "*notify",        XrmoptionNoArg,        "FALSE"},
  103.     {"-daemon",        "*daemon",        XrmoptionNoArg,        "TRUE"},
  104.     {"-verbose",    "*verbose",        XrmoptionNoArg,        "TRUE"},
  105.     {"-exitOnFail", "*exitOnFail",    XrmoptionNoArg,        "TRUE"},
  106. };
  107.  
  108. #ifdef ultrix
  109. #define USE_FILE
  110. #define FILE_NAME   "/dev/xcons"
  111. #endif
  112.  
  113. #ifndef USE_FILE
  114. #include    <sys/ioctl.h>
  115. #ifdef SVR4
  116. #include    <termios.h>
  117. #include    <sys/stropts.h>        /* for I_PUSH */
  118. #endif
  119.  
  120. #ifdef TIOCCONS
  121. #define USE_PTY
  122. static int  tty_fd, pty_fd;
  123. static char ttydev[64], ptydev[64];
  124. #endif
  125. #endif
  126.  
  127. #if defined(SYSV) && defined(SYSV386)
  128. #define USE_OSM
  129. #endif
  130.  
  131. static void inputReady ();
  132.  
  133. static
  134. OpenConsole ()
  135. {
  136.     input = 0;
  137.     if (app_resources.file)
  138.     {
  139.     if (!strcmp (app_resources.file, "console"))
  140.     {
  141.         struct stat sbuf;
  142.         /* must be owner and have read/write permission */
  143.         if (!stat("/dev/console", &sbuf) &&
  144.         (sbuf.st_uid == getuid()) &&
  145.         !access("/dev/console", R_OK|W_OK))
  146.         {
  147. #ifdef USE_FILE
  148.             input = fopen (FILE_NAME, "r");
  149. #endif
  150. #ifdef USE_PTY
  151.         int    on = 1;
  152.  
  153.         if (get_pty (&pty_fd, &tty_fd, ttydev, ptydev) == 0 &&
  154.             ioctl (tty_fd, TIOCCONS, (char *) &on) != -1)
  155.         {
  156.             input = fdopen (pty_fd, "r");
  157.         }
  158. #endif
  159.         }
  160. #ifdef USE_OSM
  161.         /* Don't have to be owner of /dev/console when using /dev/osm. */
  162.         input = fdopen(osm_pipe(), "r");
  163. #endif
  164.         if (input && app_resources.verbose)
  165.         {
  166.         char    *hostname;
  167.         TextAppend (text, "Console log for ", 16);
  168.         hostname = mit_console_name + MIT_CONSOLE_LEN;
  169.         TextAppend (text, hostname, strlen (hostname));
  170.         TextAppend (text, "\n", 1);
  171.         }
  172.     }
  173.     else
  174.     {
  175.         input = fopen (app_resources.file, "r");
  176.     }
  177.     if (!input)
  178.     {
  179.         if (app_resources.exitOnFail)
  180.         exit(0);
  181.         TextAppend (text, "Couldn't open ", 14);
  182.         TextAppend (text, app_resources.file, strlen (app_resources.file));
  183.         TextAppend (text, "\n", 1);
  184.     }
  185.     }
  186.     else
  187.     input = stdin;
  188.  
  189.     if (input)
  190.     {
  191.     input_id = XtAddInput (fileno (input), (XtPointer) XtInputReadMask,
  192.                    inputReady, (XtPointer) text);
  193.     }
  194. }
  195.  
  196.  
  197. static
  198. CloseConsole ()
  199. {
  200.     if (input) {
  201.     XtRemoveInput (input_id);
  202.     fclose (input);
  203.     }
  204. #ifdef USE_PTY
  205.     close (tty_fd);
  206. #endif
  207. }
  208.  
  209. /*ARGSUSED*/
  210. static void
  211. Quit (widget, event, params, num_params)
  212.     Widget widget;
  213.     XEvent *event;
  214.     String *params;
  215.     Cardinal *num_params;
  216. {
  217.     exit (0);
  218. }
  219.  
  220. extern char *malloc ();
  221.  
  222. static void
  223. Notify ()
  224. {
  225.     Arg        arglist[1];
  226.     char    *oldName;
  227.     char    *newName;
  228.  
  229.     if (!iconified || !app_resources.notify || notified)
  230.     return;
  231.     XtSetArg (arglist[0], XtNiconName, &oldName);
  232.     XtGetValues (top, arglist, 1);
  233.     newName = malloc (strlen (oldName) + 3);
  234.     if (!newName)
  235.     return;
  236.     sprintf (newName, "%s *", oldName);
  237.     XtSetArg (arglist[0], XtNiconName, newName);
  238.     XtSetValues (top, arglist, 1);
  239.     free (newName);
  240.     notified = True;
  241. }
  242.  
  243. /*ARGSUSED*/
  244. static void
  245. Deiconified (widget, event, params, num_params)
  246.     Widget widget;
  247.     XEvent *event;
  248.     String *params;
  249.     Cardinal *num_params;
  250. {
  251.     Arg        arglist[1];
  252.     char    *oldName;
  253.     char    *newName;
  254.     int        oldlen;
  255.  
  256.     iconified = False;
  257.     if (!app_resources.notify || !notified)
  258.     return;
  259.     XtSetArg (arglist[0], XtNiconName, &oldName);
  260.     XtGetValues (top, arglist, 1);
  261.     oldlen = strlen (oldName);
  262.     if (oldlen >= 2) {
  263.         newName = malloc (oldlen - 1);
  264.         if (!newName)
  265.         return;
  266.         strncpy (newName, oldName, oldlen - 2);
  267.     newName[oldlen - 2] = '\0';
  268.         XtSetArg (arglist[0], XtNiconName, newName);
  269.         XtSetValues (top, arglist, 1);
  270.         free (newName);
  271.     }
  272.     notified = False;
  273. }
  274.  
  275. /*ARGSUSED*/
  276. static void
  277. Iconified (widget, event, params, num_params)
  278.     Widget widget;
  279.     XEvent *event;
  280.     String *params;
  281.     Cardinal *num_params;
  282. {
  283.     iconified = True;
  284. }
  285.  
  286. /*ARGSUSED*/
  287. static void
  288. Clear (widget, event, params, num_params)
  289.     Widget widget;
  290.     XEvent *event;
  291.     String *params;
  292.     Cardinal *num_params;
  293. {
  294.     long        last;
  295.     XawTextBlock    block;
  296.  
  297.     last = TextLength (text);
  298.     block.ptr = "";
  299.     block.firstPos = 0;
  300.     block.length = 0;
  301.     block.format = FMT8BIT;
  302.     TextReplace (text, 0, last, &block);
  303. }
  304.  
  305. static XtActionsRec actions[] = {
  306.     "Quit",        Quit,
  307.     "Iconified",    Iconified,
  308.     "Deiconified",  Deiconified,
  309.     "Clear",        Clear,
  310. };
  311.  
  312. static void
  313. stripNonprint (b)
  314.     char    *b;
  315. {
  316.     char    *c;
  317.  
  318.     c = b;
  319.     while (*b)
  320.     {
  321.     if (isprint (*b) || isspace (*b) && *b != '\r')
  322.     {
  323.         if (c != b)
  324.         *c = *b;
  325.         ++c;
  326.     }
  327.     ++b;
  328.     }
  329.     *c = '\0';
  330. }
  331.  
  332. static void
  333. inputReady (w, source, id)
  334.     XtPointer    w;
  335.     int        *source;
  336.     XtInputId    *id;
  337. {
  338.     char    buffer[1025];
  339.     int        n;
  340.  
  341.     n = read (*source, buffer, sizeof (buffer) - 1);
  342.     if (n <= 0)
  343.     {
  344.     fclose (input);
  345.     XtRemoveInput (*id);
  346.     }
  347.     Notify ();
  348.     buffer[n] = '\0';
  349.     if (app_resources.stripNonprint)
  350.     {
  351.     stripNonprint (buffer);
  352.     n = strlen (buffer);
  353.     }
  354.     TextAppend ((Widget) text, buffer, n);
  355. }
  356.  
  357. static Boolean
  358. ConvertSelection (w, selection, target, type, value, length, format)
  359.     Widget w;
  360.     Atom *selection, *target, *type;
  361.     XtPointer *value;
  362.     unsigned long *length;
  363.     int *format;
  364. {
  365.     Display* d = XtDisplay(w);
  366.     XSelectionRequestEvent* req =
  367.     XtGetSelectionRequest(w, *selection, (XtRequestId)NULL);
  368.  
  369.     if (*target == XA_TARGETS(d)) {
  370.     Atom* targetP;
  371.     Atom* std_targets;
  372.     unsigned long std_length;
  373.     XmuConvertStandardSelection(w, req->time, selection, target, type,
  374.                   (caddr_t*)&std_targets, &std_length, format);
  375.     *value = (XtPointer)XtMalloc(sizeof(Atom)*(std_length + 5));
  376.     targetP = *(Atom**)value;
  377.     *targetP++ = XA_STRING;
  378.     *targetP++ = XA_TEXT(d);
  379.     *targetP++ = XA_LENGTH(d);
  380.     *targetP++ = XA_LIST_LENGTH(d);
  381.     *targetP++ = XA_CHARACTER_POSITION(d);
  382.     *length = std_length + (targetP - (*(Atom **) value));
  383.     bcopy((char*)std_targets, (char*)targetP, sizeof(Atom)*std_length);
  384.     XtFree((char*)std_targets);
  385.     *type = XA_ATOM;
  386.     *format = 32;
  387.     return True;
  388.     }
  389.  
  390.     if (*target == XA_LIST_LENGTH(d) ||
  391.     *target == XA_LENGTH(d))
  392.     {
  393.         long * temp;
  394.         
  395.         temp = (long *) XtMalloc(sizeof(long));
  396.         if (*target == XA_LIST_LENGTH(d))
  397.             *temp = 1L;
  398.         else            /* *target == XA_LENGTH(d) */
  399.             *temp = (long) TextLength (text);
  400.         
  401.         *value = (XtPointer) temp;
  402.         *type = XA_INTEGER;
  403.         *length = 1L;
  404.         *format = 32;
  405.         return True;
  406.     }
  407.     
  408.     if (*target == XA_CHARACTER_POSITION(d))
  409.     {
  410.         long * temp;
  411.         
  412.         temp = (long *) XtMalloc(2 * sizeof(long));
  413.         temp[0] = (long) 0;
  414.         temp[1] = TextLength (text);
  415.         *value = (XtPointer) temp;
  416.         *type = XA_SPAN(d);
  417.         *length = 2L;
  418.         *format = 32;
  419.         return True;
  420.     }
  421.     
  422.     if (*target == XA_STRING ||
  423.       *target == XA_TEXT(d) ||
  424.       *target == XA_COMPOUND_TEXT(d))
  425.     {
  426.     extern char *_XawTextGetSTRING();
  427.         if (*target == XA_COMPOUND_TEXT(d))
  428.         *type = *target;
  429.         else
  430.         *type = XA_STRING;
  431.     *length = TextLength (text);
  432.         *value = (XtPointer)_XawTextGetSTRING((TextWidget) text, 0, *length);
  433.         *format = 8;
  434.     /*
  435.      * Drop our connection to the file; the new console program
  436.      * will open as soon as it receives the selection contents; there
  437.      * is a small window where console output will not be redirected,
  438.      * but I see no way of avoiding that without having two programs
  439.      * attempt to redirect console output at the same time, which seems
  440.      * worse
  441.      */
  442.     CloseConsole ();
  443.         return True;
  444.     }
  445.     
  446.     if (XmuConvertStandardSelection(w, req->time, selection, target, type,
  447.                     (caddr_t *)value, length, format))
  448.     return True;
  449.  
  450.     return False;
  451. }
  452.  
  453. static void
  454. LoseSelection (w, selection)
  455.     Widget  w;
  456.     Atom    *selection;
  457. {
  458.     Quit ();
  459. }
  460.  
  461. /*ARGSUSED*/
  462. static void
  463. InsertSelection (w, client_data, selection, type, value, length, format)
  464.     Widget        w;
  465.     XtPointer        client_data;
  466.     Atom        *selection, *type;
  467.     XtPointer        value;
  468.     unsigned long   *length;
  469.     int            *format;
  470. {
  471.     if (*type != XT_CONVERT_FAIL)
  472.     TextInsert (text, (char *) value, *length);
  473.     XtOwnSelection(top, mit_console, CurrentTime,
  474.            ConvertSelection, LoseSelection, NULL);
  475.     OpenConsole ();
  476. }
  477.  
  478.  
  479. main (argc, argv)
  480.     char    **argv;
  481. {
  482.     Arg arglist[10];
  483.     Cardinal num_args;
  484.     char     *hostname;
  485.  
  486.     top = XtInitialize ("xconsole", "XConsole", options, XtNumber (options),
  487.             &argc, argv);
  488.     XtGetApplicationResources (top, (XtPointer)&app_resources, resources,
  489.                    XtNumber (resources), NULL, 0);
  490.  
  491.     if (app_resources.daemon)
  492.     if (fork ()) exit (0);
  493.     XtAddActions (actions, XtNumber (actions));
  494.     
  495.     text = XtCreateManagedWidget ("text", asciiTextWidgetClass,
  496.                   top, NULL, 0);
  497.     
  498.     XtRealizeWidget (top);
  499.     num_args = 0;
  500.     XtSetArg(arglist[num_args], XtNiconic, &iconified); num_args++;
  501.     XtGetValues(top, arglist, num_args);
  502.     if (iconified)
  503.     Iconified ();
  504.     else
  505.     Deiconified ();
  506.     wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW",
  507.                    False);
  508.     (void) XSetWMProtocols (XtDisplay(top), XtWindow(top),
  509.                             &wm_delete_window, 1);
  510.  
  511.     XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255);
  512.  
  513.     mit_console = XInternAtom(XtDisplay(top), mit_console_name, False);
  514.  
  515.     if (XGetSelectionOwner (XtDisplay (top), mit_console))
  516.     {
  517.     XtGetSelectionValue(top, mit_console, XA_STRING, InsertSelection,
  518.                 NULL, CurrentTime);
  519.     }
  520.     else
  521.     {
  522.     XtOwnSelection(top, mit_console, CurrentTime,
  523.                ConvertSelection, LoseSelection, NULL);
  524.     OpenConsole ();
  525.     }
  526.     XtMainLoop ();
  527.     return 0;
  528. }
  529.  
  530. static long TextLength (w)
  531.     Widget  w;
  532. {
  533.     return XawTextSourceScan (XawTextGetSource (w),
  534.                   (XawTextPosition) 0,
  535.                    XawstAll, XawsdRight, 1, TRUE);
  536. }
  537.  
  538. TextReplace (w, start, end, block)
  539.     Widget        w;
  540.     XawTextBlock    *block;
  541. {
  542.     Arg            arg;
  543.     Widget        source;
  544.     XawTextEditType edit_mode;
  545.  
  546.     source = XawTextGetSource (w);
  547.     XtSetArg (arg, XtNeditType, &edit_mode);
  548.     XtGetValues (source, &arg, ONE);
  549.     XtSetArg (arg, XtNeditType, XawtextEdit);
  550.     XtSetValues (source, &arg, ONE);
  551.     XawTextReplace (w, start, end, block);
  552.     XtSetArg (arg, XtNeditType, edit_mode);
  553.     XtSetValues (source, &arg, ONE);
  554. }
  555.  
  556. TextAppend (w, s, len)
  557.     Widget  w;
  558.     char    *s;
  559. {
  560.     long        last, current;
  561.     XawTextBlock    block;
  562.  
  563.     current = XawTextGetInsertionPoint (w);
  564.     last = TextLength (w);
  565.     block.ptr = s;
  566.     block.firstPos = 0;
  567.     block.length = len;
  568.     block.format = FMT8BIT;
  569.     TextReplace (w, last, last, &block);
  570.     if (current == last)
  571.     XawTextSetInsertionPoint (w, last + block.length);
  572. }
  573.  
  574. TextInsert (w, s, len)
  575.     Widget  w;
  576.     char    *s;
  577. {
  578.     XawTextBlock    block;
  579.     long        current;
  580.  
  581.     current = XawTextGetInsertionPoint (w);
  582.     block.ptr = s;
  583.     block.firstPos = 0;
  584.     block.length = len;
  585.     block.format = FMT8BIT;
  586.     TextReplace (w, 0, 0, &block);
  587.     if (current == 0)
  588.     XawTextSetInsertionPoint (w, len);
  589. }
  590.  
  591. #ifdef USE_PTY
  592. /* This function opens up a pty master and stuffs it's value into pty.
  593.  * If it finds one, it returns a value of 0.  If it does not find one,
  594.  * it returns a value of !0.  This routine is designed to be re-entrant,
  595.  * so that if a pty master is found and later, we find that the slave
  596.  * has problems, we can re-enter this function and get another one.
  597.  */
  598.  
  599. #include    "../xterm/ptyx.h"
  600.  
  601. get_pty (pty, tty, ttydev, ptydev)
  602.     int        *pty, *tty;
  603.     char    *ttydev, *ptydev;
  604. {
  605. #ifdef SVR4
  606.     if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) {
  607.         return 1;
  608.     }
  609.     grantpt(*pty);
  610.     unlockpt(*pty);
  611.     strcpy(ttydev, ptsname(*pty));
  612.     if ((*tty = open(ttydev, O_RDWR)) >= 0) {
  613.         (void)ioctl(*tty, I_PUSH, "ttcompat");
  614.         return 0;
  615.     }
  616.     if (*pty >= 0)
  617.         close (*pty);
  618. #else /* !SVR4, need lots of code */
  619. #ifdef USE_GET_PSEUDOTTY
  620.     if ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 &&
  621.         (*tty = open (ttydev, O_RDWR)) >= 0)
  622.         return 0;
  623.     if (*pty >= 0)
  624.         close (*pty);
  625. #else
  626.     static int devindex, letter = 0;
  627.  
  628. #if defined(umips) && defined (SYSTYPE_SYSV)
  629.     struct stat fstat_buf;
  630.  
  631.     *pty = open ("/dev/ptc", O_RDWR);
  632.     if (*pty < 0 || (fstat (*pty, &fstat_buf)) < 0) {
  633.       return(1);
  634.     }
  635.     sprintf (ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
  636.     sprintf (ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev));
  637.     if ((*tty = open (ttydev, O_RDWR)) >= 0) {
  638.         /* got one! */
  639.         return(0);
  640.     }
  641.     close (*pty);
  642. #else /* not (umips && SYSTYPE_SYSV) */
  643. #ifdef CRAY
  644.     for (; devindex < 256; devindex++) {
  645.         sprintf (ttydev, "/dev/ttyp%03d", devindex);
  646.         sprintf (ptydev, "/dev/pty/%03d", devindex);
  647.  
  648.         if ((*pty = open (ptydev, O_RDWR)) >= 0 &&
  649.         (*tty = open (ttydev, O_RDWR)) >= 0)
  650.         {
  651.         /* We need to set things up for our next entry
  652.          * into this function!
  653.          */
  654.         (void) devindex++;
  655.         return(0);
  656.         }
  657.         if (*pty >= 0)
  658.         close (*pty);
  659.     }
  660. #else /* !CRAY */
  661.     strcpy (ttydev, "/dev/ttyxx");
  662.     strcpy (ptydev, "/dev/ptyxx");
  663.     while (PTYCHAR1[letter]) {
  664.         ttydev [strlen(ttydev) - 2]  = ptydev [strlen(ptydev) - 2] =
  665.             PTYCHAR1 [letter];
  666.  
  667.         while (PTYCHAR2[devindex]) {
  668.         ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] =
  669.             PTYCHAR2 [devindex];
  670.         if ((*pty = open (ptydev, O_RDWR)) >= 0 &&
  671.             (*tty = open (ttydev, O_RDWR)) >= 0)
  672.         {
  673.             /* We need to set things up for our next entry
  674.              * into this function!
  675.              */
  676.             (void) devindex++;
  677.             return(0);
  678.         }
  679.         if (*pty >= 0)
  680.             close (*pty);
  681.         devindex++;
  682.         }
  683.         devindex = 0;
  684.         (void) letter++;
  685.     }
  686. #endif /* CRAY else not CRAY */
  687. #endif /* umips && SYSTYPE_SYSV */
  688. #endif /* USE_GET_PSEUDOTTY */
  689. #endif /* SVR4 */
  690.     /* We were unable to allocate a pty master!  Return an error
  691.      * condition and let our caller terminate cleanly.
  692.      */
  693.     return(1);
  694. }
  695. #endif
  696.  
  697. #ifdef USE_OSM
  698. /*
  699.  * On SYSV386 there is a special device, /dev/osm, where system messages
  700.  * are sent.  Problem is that we can't perform a select(2) on this device.
  701.  * So this routine creates a streams-pty where one end reads the device and
  702.  * sends the output to xconsole.
  703.  */
  704. osm_pipe()
  705. {
  706.   int tty, pid;
  707.   char ttydev[64];
  708.     
  709.   if ((tty = open("/dev/ptmx", O_RDWR)) < 0)  return -1;
  710.  
  711.   grantpt(tty);
  712.   unlockpt(tty);
  713.   strcpy(ttydev, (char *)ptsname(tty));
  714.  
  715.   if ((pid = fork()) == 0) {
  716.     int pty, osm, buf, nbytes;
  717.  
  718.     pty = open(ttydev, O_RDWR);
  719.     osm = open("/dev/osm", O_RDWR);
  720.     while ((nbytes = read(osm, &buf, sizeof(buf))) >= 0)
  721.       write(pty, &buf, nbytes);
  722.   }
  723.   return tty;
  724. }
  725. #endif  /* USE_OSM */
  726.