Merge branch '3243_usmenu_view_man'
[midnight-commander.git] / src / cons.handler.c
blobdcf9d1781f19b521c759569b9ded1a9a03335482
1 /*
2 Client interface for General purpose Linux console save/restore server
4 Copyright (C) 1994-2014
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /** \file cons.handler.c
24 * \brief Source: client %interface for General purpose Linux console save/restore server
27 #include <config.h>
29 #include <stdlib.h>
30 #include <sys/wait.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #ifdef __FreeBSD__
36 #include <sys/consio.h>
37 #ifdef HAVE_SYS_IOCTL_H
38 #include <sys/ioctl.h>
39 #endif
40 #endif
42 #include "lib/global.h"
44 #include "lib/unixcompat.h"
45 #include "lib/tty/tty.h"
46 #include "lib/skin.h" /* tty_set_normal_attrs */
47 #include "lib/tty/win.h"
48 #include "lib/util.h" /* mc_build_filename() */
50 #include "consaver/cons.saver.h"
52 /*** global variables ****************************************************************************/
54 #ifdef __linux__
55 int cons_saver_pid = 1;
56 #endif /* __linux__ */
58 /*** file scope macro definitions ****************************************************************/
60 #if defined(__FreeBSD__)
61 #define FD_OUT 1
62 #define cursor_to(x, y) \
63 do \
64 { \
65 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
66 fflush(stdout); \
67 } while (0)
68 #endif /* __linux__ */
70 /*** file scope type declarations ****************************************************************/
72 /*** file scope variables ************************************************************************/
74 #ifdef __linux__
75 /* The cons saver can't have a pid of 1, used to prevent bunches of
76 * #ifdef linux */
77 static int pipefd1[2] = { -1, -1 };
78 static int pipefd2[2] = { -1, -1 };
79 #elif defined(__FreeBSD__)
80 static struct scrshot screen_shot;
81 static struct vid_info screen_info;
82 #endif /* __linux__ */
84 /*** file scope functions ************************************************************************/
85 /* --------------------------------------------------------------------------------------------- */
87 #ifdef __linux__
88 static void
89 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
91 unsigned char message = 0;
92 unsigned short bytes = 0;
93 int i;
94 ssize_t ret;
96 /* Is tty console? */
97 if (mc_global.tty.console_flag == '\0')
98 return;
99 /* Paranoid: Is the cons.saver still running? */
100 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
102 cons_saver_pid = 0;
103 mc_global.tty.console_flag = '\0';
104 return;
107 /* Send command to the console handler */
108 message = CONSOLE_CONTENTS;
109 ret = write (pipefd1[1], &message, 1);
110 /* Check for outdated cons.saver */
111 ret = read (pipefd2[0], &message, 1);
112 if (message != CONSOLE_CONTENTS)
113 return;
115 /* Send the range of lines that we want */
116 ret = write (pipefd1[1], &begin_line, 1);
117 ret = write (pipefd1[1], &end_line, 1);
118 /* Read the corresponding number of bytes */
119 ret = read (pipefd2[0], &bytes, 2);
121 /* Read the bytes and output them */
122 for (i = 0; i < bytes; i++)
124 if ((i % COLS) == 0)
125 tty_gotoyx (starty + (i / COLS), 0);
126 ret = read (pipefd2[0], &message, 1);
127 tty_print_char (message);
130 /* Read the value of the mc_global.tty.console_flag */
131 ret = read (pipefd2[0], &message, 1);
132 (void) ret;
135 /* --------------------------------------------------------------------------------------------- */
137 static void
138 handle_console_linux (console_action_t action)
140 int status;
142 switch (action)
144 case CONSOLE_INIT:
145 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
146 status = close (pipefd1[1]);
147 status = close (pipefd2[0]);
148 /* Create two pipes for communication */
149 if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
151 mc_global.tty.console_flag = '\0';
152 break;
154 /* Get the console saver running */
155 cons_saver_pid = fork ();
156 if (cons_saver_pid < 0)
158 /* Cannot fork */
159 /* Delete pipes */
160 status = close (pipefd1[1]);
161 status = close (pipefd1[0]);
162 status = close (pipefd2[1]);
163 status = close (pipefd2[0]);
164 mc_global.tty.console_flag = '\0';
166 else if (cons_saver_pid > 0)
168 /* Parent */
169 /* Close the extra pipe ends */
170 status = close (pipefd1[0]);
171 status = close (pipefd2[1]);
172 /* Was the child successful? */
173 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
174 if (mc_global.tty.console_flag == '\0')
176 pid_t ret;
177 status = close (pipefd1[1]);
178 status = close (pipefd2[0]);
179 ret = waitpid (cons_saver_pid, &status, 0);
180 (void) ret;
183 else
185 /* Child */
186 char *tty_name;
188 /* Close the extra pipe ends */
189 status = close (pipefd1[1]);
190 status = close (pipefd2[0]);
191 tty_name = ttyname (0);
192 /* Bind the pipe 0 to the standard input */
195 if (dup2 (pipefd1[0], STDIN_FILENO) == -1)
196 break;
197 status = close (pipefd1[0]);
198 /* Bind the pipe 1 to the standard output */
199 if (dup2 (pipefd2[1], STDOUT_FILENO) == -1)
200 break;
202 status = close (pipefd2[1]);
203 /* Bind standard error to /dev/null */
204 status = open ("/dev/null", O_WRONLY);
205 if (dup2 (status, STDERR_FILENO) == -1)
206 break;
207 status = close (status);
208 if (tty_name != NULL)
210 char *mc_conssaver;
212 /* Exec the console save/restore handler */
213 mc_conssaver = mc_build_filename (SAVERDIR, "cons.saver", NULL);
214 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
216 /* Console is not a tty or execl() failed */
218 while (0);
219 mc_global.tty.console_flag = '\0';
220 status = write (1, &mc_global.tty.console_flag, 1);
221 my_exit (3);
222 } /* if (cons_saver_pid ...) */
223 break;
225 case CONSOLE_DONE:
226 case CONSOLE_SAVE:
227 case CONSOLE_RESTORE:
228 /* Is tty console? */
229 if (mc_global.tty.console_flag == '\0')
230 return;
231 /* Paranoid: Is the cons.saver still running? */
232 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
234 cons_saver_pid = 0;
235 mc_global.tty.console_flag = '\0';
236 return;
238 /* Send command to the console handler */
239 status = write (pipefd1[1], &action, 1);
240 if (action != CONSOLE_DONE)
242 /* Wait the console handler to do its job */
243 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
245 if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
247 /* We are done -> Let's clean up */
248 pid_t ret;
249 close (pipefd1[1]);
250 close (pipefd2[0]);
251 ret = waitpid (cons_saver_pid, &status, 0);
252 (void) ret;
253 mc_global.tty.console_flag = '\0';
255 break;
256 default:
257 break;
261 #elif defined(__FreeBSD__)
263 /* --------------------------------------------------------------------------------------------- */
265 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
266 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
269 static void
270 console_init (void)
272 if (mc_global.tty.console_flag != '\0')
273 return;
275 screen_info.size = sizeof (screen_info);
276 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
277 return;
279 memset (&screen_shot, 0, sizeof (screen_shot));
280 screen_shot.xsize = screen_info.mv_csz;
281 screen_shot.ysize = screen_info.mv_rsz;
282 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
283 if (screen_shot.buf != NULL)
284 mc_global.tty.console_flag = '\001';
287 /* --------------------------------------------------------------------------------------------- */
289 static void
290 set_attr (unsigned attr)
293 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
294 * to indices for ANSI sequences (red=1, green=2, blue=4).
296 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
297 int bc, tc;
299 tc = attr & 0xF;
300 bc = (attr >> 4) & 0xF;
302 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
303 color_map[tc & 7], color_map[bc & 7]);
306 /* --------------------------------------------------------------------------------------------- */
308 static void
309 console_restore (void)
311 int i, last;
313 if (mc_global.tty.console_flag == '\0')
314 return;
316 cursor_to (0, 0);
318 /* restoring all content up to cursor position */
319 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
320 for (i = 0; i < last; ++i)
322 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
323 putc (screen_shot.buf[i] & 0xFF, stdout);
326 /* restoring cursor color */
327 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
329 fflush (stdout);
332 /* --------------------------------------------------------------------------------------------- */
334 static void
335 console_shutdown (void)
337 if (mc_global.tty.console_flag == '\0')
338 return;
340 g_free (screen_shot.buf);
342 mc_global.tty.console_flag = '\0';
345 /* --------------------------------------------------------------------------------------------- */
347 static void
348 console_save (void)
350 int i;
351 scrmap_t map;
352 scrmap_t revmap;
354 if (mc_global.tty.console_flag == '\0')
355 return;
357 /* screen_info.size is already set in console_init() */
358 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
360 console_shutdown ();
361 return;
364 /* handle console resize */
365 if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
367 console_shutdown ();
368 console_init ();
371 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
373 console_shutdown ();
374 return;
377 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
379 console_shutdown ();
380 return;
383 for (i = 0; i < 256; i++)
385 char *p = memchr (map.scrmap, i, 256);
386 revmap.scrmap[i] = p ? p - map.scrmap : i;
389 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
391 /* *INDENT-OFF* */
392 screen_shot.buf[i] = (screen_shot.buf[i] & 0xff00)
393 | (unsigned char) revmap.scrmap[screen_shot.buf[i] & 0xff];
394 /* *INDENT-ON* */
398 /* --------------------------------------------------------------------------------------------- */
400 static void
401 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
403 int col, line;
404 char c;
406 if (mc_global.tty.console_flag == '\0')
407 return;
409 for (line = begin_line; line <= end_line; line++)
411 tty_gotoyx (starty + line - begin_line, 0);
412 for (col = 0; col < min (COLS, screen_info.mv_csz); col++)
414 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
415 tty_print_char (c);
420 /* --------------------------------------------------------------------------------------------- */
422 static void
423 handle_console_freebsd (console_action_t action)
425 switch (action)
427 case CONSOLE_INIT:
428 console_init ();
429 break;
431 case CONSOLE_DONE:
432 console_shutdown ();
433 break;
435 case CONSOLE_SAVE:
436 console_save ();
437 break;
439 case CONSOLE_RESTORE:
440 console_restore ();
441 break;
442 default:
443 break;
446 #endif /* __FreeBSD__ */
448 /* --------------------------------------------------------------------------------------------- */
449 /*** public functions ****************************************************************************/
450 /* --------------------------------------------------------------------------------------------- */
452 void
453 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
455 tty_set_normal_attrs ();
457 if (look_for_rxvt_extensions ())
459 show_rxvt_contents (starty, begin_line, end_line);
460 return;
462 #ifdef __linux__
463 show_console_contents_linux (starty, begin_line, end_line);
464 #elif defined (__FreeBSD__)
465 show_console_contents_freebsd (starty, begin_line, end_line);
466 #else
467 mc_global.tty.console_flag = '\0';
468 #endif
471 /* --------------------------------------------------------------------------------------------- */
473 void
474 handle_console (console_action_t action)
476 (void) action;
478 if (look_for_rxvt_extensions ())
479 return;
481 #ifdef __linux__
482 handle_console_linux (action);
483 #elif defined (__FreeBSD__)
484 handle_console_freebsd (action);
485 #endif
488 /* --------------------------------------------------------------------------------------------- */