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