2 * Copyright (c) 1992, 2015, Oracle and/or its affiliates. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
26 * fbconsole - fallback console
39 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/strredir.h>
47 static char LogPath
[MAXPATHLEN
]; /* pathname of log file */
50 * Default settings to use if they can't actually be obtained from a
51 * descriptor relevant to the application.
53 * XXX: These settings shouldn't be used unless absolutely necessary, since
54 * they're almost certain to get out of sync with the kernel's defaults
55 * (which is what they're intended to be).
57 static struct termios termios_dflt
= {
58 BRKINT
|ICRNL
|IXON
|IGNPAR
|IMAXBEL
, /* input modes */
59 OPOST
|ONLCR
, /* output modes */
60 B9600
|(B9600
<< IBSHIFT
)|CS8
|HUPCL
|CREAD
, /* control modes */
61 ISIG
|ICANON
|ECHO
|IEXTEN
|ECHOE
|ECHOK
|ECHOCTL
|ECHOKE
, /* local modes */
62 /* control characters */
76 CFLUSH
, /* VDISCARD */
77 CWERASE
, /* VWERASE */
85 * Returns a file descriptor which has had the console redirected to it
87 * This version (unused) opens a pipe and redirects the console to it.
95 if (pipe(fds
) == -1) {
96 fprintf(stderr
,"Couldn't open console pipes\n");
101 if ((fdcons
= open("/dev/console", O_RDONLY
)) == -1) {
102 fprintf(stderr
,"Couldn't open /dev/console\n");
107 if (ioctl(fdcons
, SRIOCSREDIR
, fds
[0]) == -1) {
108 fprintf(stderr
,"Couldn't redirect console to console pipe\n");
120 * Opens a pty, copies tty settings into it from /dev/console, and redirects
121 * console output to it. Returns the master end of the pty.
130 struct termios termios
;
132 if ((console
= open("/dev/console", O_RDONLY
| O_NOCTTY
, 0)) == -1) {
133 perror("fbconsole: open /dev/console");
137 if ((master
= open("/dev/ptmx", O_RDWR
, 0)) == -1) {
138 perror("fbconsole: open /dev/ptmx");
142 if (grantpt(master
) == -1) {
143 fputs("fbconsole: grantpt failed\n", stderr
);
147 if (unlockpt(master
) == -1) {
148 fputs("fbconsole: unlockpt failed\n", stderr
);
152 if ((slavename
= ptsname(master
)) == NULL
) {
153 fputs("fbconsole: ptsname failed\n", stderr
);
158 fprintf(stderr
, "slavename = \"%s\"\n", slavename
);
161 if ((slave
= open(slavename
, O_RDWR
, 0)) == -1) {
162 perror("fbconsole: open slave");
166 if (ioctl(slave
, I_PUSH
, "ptem") == -1) {
167 perror("fbconsole: push ptem");
171 if (ioctl(slave
, I_PUSH
, "ldterm") == -1) {
172 perror("fbconsole: push ldterm");
177 * Propagate tty settings from the real console to the new console.
178 * If the erase character is zero, apply default settings to the new
179 * console. If the erase character is nonzero, leave most of the
180 * settings intact and apply default values only to the modes and to
181 * the EOF and EOL character. (Why apply defaults for EOF and EOL?)
183 * Code originally taken from XView, lib/libxview/ttysw/tty_gtty.c
186 if (tcgetattr(console
, &termios
) == -1) {
187 perror("fbconsole: tcgetattr");
191 if (termios
.c_cc
[VERASE
] == 0) {
192 termios
= termios_dflt
;
194 termios
.c_iflag
= termios_dflt
.c_iflag
;
195 termios
.c_oflag
= termios_dflt
.c_oflag
;
196 termios
.c_cflag
= termios_dflt
.c_cflag
;
197 termios
.c_lflag
= termios_dflt
.c_lflag
;
198 termios
.c_cc
[VEOF
] = termios_dflt
.c_cc
[VEOF
];
199 termios
.c_cc
[VEOL
] = termios_dflt
.c_cc
[VEOL
];
202 if (tcsetattr(slave
, TCSANOW
, &termios
) == -1) {
203 perror("fbconsole: tcsetattr");
207 /* redirect console output into the slave side */
209 if (ioctl(console
, SRIOCSREDIR
, slave
) == -1) {
210 perror("fbconsole: ioctl SRIOCSREDIR");
220 * Opens the console log file; returns a file descriptor
232 tmpName
= getenv("TMPDIR");
233 if (tmpName
== NULL
) {
236 if (snprintf(LogPath
, sizeof(LogPath
), "%s/wscon-%s-XXXXXX",
237 tmpName
, dpyName
) > sizeof(LogPath
)) {
240 tmpFd
= mkstemp(LogPath
);
246 if ((strcmp(path
,"-") == 0) ||
247 (strcmp(path
,"stderr") == 0)) {
250 tmpFd
= open(path
, O_WRONLY
| O_CREAT
| O_EXCL
,
255 fprintf(stderr
, "log file = \"%s\"\n", path
);
258 if ( (tmpFd
< 0) || (log
= fdopen(tmpFd
, "w")) == NULL
) {
260 "fbconsole: couldn't open console log file '%s'\n",path
);
263 setvbuf(log
, NULL
, _IONBF
, 0);
265 fchmod(fileno(log
), S_IRUSR
|S_IWUSR
);
276 if (LogPath
[0] == '\0')
279 if (unlink(LogPath
) == -1)
285 * Closes log file and exits
297 * The signal handler for SIGINT and SIGTERM.
301 SignalHandler(int sig
)
308 * DisplayErrorHandler
309 * X I/O error handler.
313 DisplayErrorHandler(Display
*dpy
)
322 * Reads a console message and writes it to the console log file
332 rcount
= read(console
, buf
, 1024);
337 (void) fwrite(buf
, rcount
, 1, log
);
342 * Waits for input from the console message pipe or the xserver.
343 * On input from the console - logs it to the console log file.
344 * On any input (or EOF) from the xserver, exits
352 struct pollfd fds
[2];
359 fds
[CONSOLE_FD
].fd
= console
;
360 fds
[CONSOLE_FD
].events
= POLLIN
;
362 fds
[XSERVER_FD
].fd
= ConnectionNumber(dpy
);
363 fds
[XSERVER_FD
].events
= POLLIN
;
367 while (poll(fds
, fdcount
, -1) >= 0) {
369 if ((dpy
!= NULL
) && (fds
[XSERVER_FD
].revents
)) {
370 while (XPending(dpy
))
371 XNextEvent(dpy
, &event
);
374 if (fds
[CONSOLE_FD
].revents
& POLLIN
) {
375 LogConsole(console
,log
);
382 * Prints a usage message
388 fprintf(stderr
,"Usage: fbconsole [-d <display>] [-f <logfile>] [-n]\n");
396 main(int argc
, char **argv
)
399 char *dpyName
= NULL
;
401 char *logFile
= NULL
;
404 int noDisplay
= False
;
406 while ((opt
= getopt(argc
, argv
, "d:f:n")) != EOF
) {
424 dpyName
= XDisplayName(dpyName
);
426 if ((dpy
= XOpenDisplay(dpyName
)) == NULL
) {
428 "Couldn't open display connection %s\n",
429 XDisplayName(dpyName
));
432 (void) XSetIOErrorHandler(DisplayErrorHandler
);
433 dpyName
= XDisplayString(dpy
);
436 console
= OpenConsole();
438 log
= OpenLog(dpyName
, logFile
);
440 (void)sigset(SIGHUP
, SignalHandler
);
441 (void)sigset(SIGINT
, SignalHandler
);
442 (void)sigset(SIGQUIT
, SignalHandler
);
443 (void)sigset(SIGTERM
, SignalHandler
);
444 (void)sigset(SIGPIPE
, SignalHandler
);
446 InputLoop(dpy
, console
, log
);