rebuild geeqie
[oi-userland.git] / components / x11 / fbconsole / src / fbconsole.c
blob368c39f4c5a005c08f934446144b2e5ea9b98372
1 /*
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
13 * Software.
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
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
33 #include <fcntl.h>
34 #include <poll.h>
35 #include <signal.h>
36 #include <stropts.h>
37 #include <termios.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/param.h>
42 #include <sys/strredir.h>
44 #include <X11/Xos.h>
45 #include <X11/Xlib.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 */
63 CINTR, /* VINTR */
64 CQUIT, /* VQUIT */
65 CERASE, /* VERASE */
66 CKILL, /* VKILL */
67 CEOT, /* VEOF */
68 CEOL, /* VEOL */
69 CEOL2, /* VEOL2 */
70 CNUL, /* VSWTCH */
71 CSTART, /* VSTART */
72 CSTOP, /* VSTOP */
73 CSUSP, /* VSUSP */
74 CDSUSP, /* VDSUSP */
75 CRPRNT, /* VRPRNT */
76 CFLUSH, /* VDISCARD */
77 CWERASE, /* VWERASE */
78 CLNEXT, /* VLNEXT */
82 #ifdef NOTDEF
84 * OpenConsole
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.
89 static int
90 OpenConsole(void)
92 int fds[2];
93 int fdcons;
95 if (pipe(fds) == -1) {
96 fprintf(stderr,"Couldn't open console pipes\n");
97 perror("pipe");
98 exit(1);
101 if ((fdcons = open("/dev/console", O_RDONLY)) == -1) {
102 fprintf(stderr,"Couldn't open /dev/console\n");
103 perror("open");
104 exit(1);
107 if (ioctl(fdcons, SRIOCSREDIR, fds[0]) == -1) {
108 fprintf(stderr,"Couldn't redirect console to console pipe\n");
109 exit(1);
112 return fds[1];
114 #endif /* NOTDEF */
118 * OpenConsole
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.
123 static int
124 OpenConsole(void)
126 int console;
127 int master;
128 int slave;
129 char *slavename;
130 struct termios termios;
132 if ((console = open("/dev/console", O_RDONLY | O_NOCTTY, 0)) == -1) {
133 perror("fbconsole: open /dev/console");
134 exit(1);
137 if ((master = open("/dev/ptmx", O_RDWR, 0)) == -1) {
138 perror("fbconsole: open /dev/ptmx");
139 exit(1);
142 if (grantpt(master) == -1) {
143 fputs("fbconsole: grantpt failed\n", stderr);
144 exit(1);
147 if (unlockpt(master) == -1) {
148 fputs("fbconsole: unlockpt failed\n", stderr);
149 exit(1);
152 if ((slavename = ptsname(master)) == NULL) {
153 fputs("fbconsole: ptsname failed\n", stderr);
154 exit(1);
157 #ifdef DEBUG
158 fprintf(stderr, "slavename = \"%s\"\n", slavename);
159 #endif
161 if ((slave = open(slavename, O_RDWR, 0)) == -1) {
162 perror("fbconsole: open slave");
163 exit(1);
166 if (ioctl(slave, I_PUSH, "ptem") == -1) {
167 perror("fbconsole: push ptem");
168 exit(1);
171 if (ioctl(slave, I_PUSH, "ldterm") == -1) {
172 perror("fbconsole: push ldterm");
173 exit(1);
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");
188 exit(1);
191 if (termios.c_cc[VERASE] == 0) {
192 termios = termios_dflt;
193 } else {
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");
204 exit(1);
207 /* redirect console output into the slave side */
209 if (ioctl(console, SRIOCSREDIR, slave) == -1) {
210 perror("fbconsole: ioctl SRIOCSREDIR");
211 exit(1);
214 return master;
219 * OpenLog
220 * Opens the console log file; returns a file descriptor
222 static FILE *
223 OpenLog(
224 const char *dpyName,
225 char *path)
227 const char *tmpName;
228 FILE *log;
229 int tmpFd;
231 if (path == NULL) {
232 tmpName = getenv("TMPDIR");
233 if (tmpName == NULL) {
234 tmpName = P_tmpdir;
236 if (snprintf(LogPath, sizeof(LogPath), "%s/wscon-%s-XXXXXX",
237 tmpName, dpyName) > sizeof(LogPath)) {
238 tmpFd = -1;
239 } else {
240 tmpFd = mkstemp(LogPath);
242 path = LogPath;
243 } else {
244 LogPath[0] = '\0';
246 if ((strcmp(path,"-") == 0) ||
247 (strcmp(path,"stderr") == 0)) {
248 return stderr;
250 tmpFd = open(path, O_WRONLY | O_CREAT | O_EXCL,
251 S_IRUSR|S_IWUSR);
254 #ifdef DEBUG
255 fprintf(stderr, "log file = \"%s\"\n", path);
256 #endif
258 if ( (tmpFd < 0) || (log = fdopen(tmpFd, "w")) == NULL) {
259 fprintf(stderr,
260 "fbconsole: couldn't open console log file '%s'\n",path);
261 exit(1);
263 setvbuf(log, NULL, _IONBF, 0);
265 fchmod(fileno(log), S_IRUSR|S_IWUSR);
267 return log;
271 * CloseLog
273 static void
274 CloseLog(void)
276 if (LogPath[0] == '\0')
277 return;
279 if (unlink(LogPath) == -1)
280 perror("unlink");
284 * CleanupAndExit
285 * Closes log file and exits
287 static void
288 CleanupAndExit(void)
290 CloseLog();
291 exit(0);
296 * SignalHandler
297 * The signal handler for SIGINT and SIGTERM.
299 /*ARGSUSED*/
300 void
301 SignalHandler(int sig)
303 CleanupAndExit();
308 * DisplayErrorHandler
309 * X I/O error handler.
311 /*ARGSUSED*/
313 DisplayErrorHandler(Display *dpy)
315 CleanupAndExit();
316 return 0;
321 * LogConsole
322 * Reads a console message and writes it to the console log file
324 static void
325 LogConsole(
326 int console,
327 FILE *log)
329 char buf[1024];
330 int rcount;
332 rcount = read(console, buf, 1024);
334 if (rcount == -1)
335 return;
337 (void) fwrite(buf, rcount, 1, log);
341 * InputLoop
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
346 static void
347 InputLoop(
348 Display *dpy,
349 int console,
350 FILE *log)
352 struct pollfd fds[2];
353 XEvent event;
354 int fdcount = 1;
356 #define CONSOLE_FD 0
357 #define XSERVER_FD 1
359 fds[CONSOLE_FD].fd = console;
360 fds[CONSOLE_FD].events = POLLIN;
361 if (dpy != NULL) {
362 fds[XSERVER_FD].fd = ConnectionNumber(dpy);
363 fds[XSERVER_FD].events = POLLIN;
364 fdcount++;
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);
381 * Usage
382 * Prints a usage message
384 static void
385 Usage(void)
388 fprintf(stderr,"Usage: fbconsole [-d <display>] [-f <logfile>] [-n]\n");
389 exit(1);
393 * main
396 main(int argc, char **argv)
398 Display *dpy = NULL;
399 char *dpyName = NULL;
400 int console;
401 char *logFile = NULL;
402 FILE *log;
403 int opt;
404 int noDisplay = False;
406 while ((opt = getopt(argc, argv, "d:f:n")) != EOF) {
407 switch (opt) {
408 case 'd':
409 dpyName = optarg;
410 break;
411 case 'n':
412 noDisplay = True;
413 break;
414 case 'f':
415 logFile = optarg;
416 break;
417 case '?':
418 Usage();
419 break;
423 if (noDisplay) {
424 dpyName = XDisplayName(dpyName);
425 } else {
426 if ((dpy = XOpenDisplay(dpyName)) == NULL) {
427 fprintf(stderr,
428 "Couldn't open display connection %s\n",
429 XDisplayName(dpyName));
430 exit(1);
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);
448 return(0);