610db289bfc44a01e59e690aa2014263a401273a
[midnight-commander.git] / src / cons.handler.c
blob610db289bfc44a01e59e690aa2014263a401273a
1 /*
2 Client interface for General purpose Linux console save/restore server
4 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2011
6 The Free Software Foundation, Inc.
8 This file is part of the Midnight Commander.
10 The Midnight Commander is free software: you can redistribute it
11 and/or modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation, either version 3 of the License,
13 or (at your option) any later version.
15 The Midnight Commander is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /** \file cons.handler.c
25 * \brief Source: client %interface for General purpose Linux console save/restore server
28 #include <config.h>
30 #include <stdlib.h>
31 #include <sys/wait.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #ifdef __FreeBSD__
37 #include <sys/consio.h>
38 #ifdef HAVE_SYS_IOCTL_H
39 #include <sys/ioctl.h>
40 #endif
41 #endif
42 #include <unistd.h>
44 #include "lib/global.h"
46 #include "lib/tty/tty.h"
47 #include "lib/skin.h" /* tty_set_normal_attrs */
48 #include "lib/tty/win.h"
49 #include "lib/util.h" /* mc_build_filename() */
51 #include "consaver/cons.saver.h"
53 /*** global variables ****************************************************************************/
55 #ifdef __linux__
56 int cons_saver_pid = 1;
57 #endif /* __linux__ */
59 /*** file scope macro definitions ****************************************************************/
61 #if defined(__FreeBSD__)
62 #define FD_OUT 1
63 #define cursor_to(x, y) \
64 do \
65 { \
66 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
67 fflush(stdout); \
68 } while (0)
69 #endif /* __linux__ */
71 /*** file scope type declarations ****************************************************************/
73 /*** file scope variables ************************************************************************/
75 #ifdef __linux__
76 /* The cons saver can't have a pid of 1, used to prevent bunches of
77 * #ifdef linux */
78 static int pipefd1[2] = { -1, -1 };
79 static int pipefd2[2] = { -1, -1 };
80 #elif defined(__FreeBSD__)
81 static struct scrshot screen_shot;
82 static struct vid_info screen_info;
83 #endif /* __linux__ */
85 /*** file scope functions ************************************************************************/
86 /* --------------------------------------------------------------------------------------------- */
88 #ifdef __linux__
89 static void
90 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
92 unsigned char message = 0;
93 unsigned short bytes = 0;
94 int i;
95 ssize_t ret;
97 /* Is tty console? */
98 if (mc_global.tty.console_flag == '\0')
99 return;
100 /* Paranoid: Is the cons.saver still running? */
101 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
103 cons_saver_pid = 0;
104 mc_global.tty.console_flag = '\0';
105 return;
108 /* Send command to the console handler */
109 message = CONSOLE_CONTENTS;
110 ret = write (pipefd1[1], &message, 1);
111 /* Check for outdated cons.saver */
112 ret = read (pipefd2[0], &message, 1);
113 if (message != CONSOLE_CONTENTS)
114 return;
116 /* Send the range of lines that we want */
117 ret = write (pipefd1[1], &begin_line, 1);
118 ret = write (pipefd1[1], &end_line, 1);
119 /* Read the corresponding number of bytes */
120 ret = read (pipefd2[0], &bytes, 2);
122 /* Read the bytes and output them */
123 for (i = 0; i < bytes; i++)
125 if ((i % COLS) == 0)
126 tty_gotoyx (starty + (i / COLS), 0);
127 ret = read (pipefd2[0], &message, 1);
128 tty_print_char (message);
131 /* Read the value of the mc_global.tty.console_flag */
132 ret = read (pipefd2[0], &message, 1);
135 /* --------------------------------------------------------------------------------------------- */
137 static void
138 handle_console_linux (console_action_t action)
140 char *tty_name;
141 char *mc_conssaver;
142 int status;
144 switch (action)
146 case CONSOLE_INIT:
147 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
148 status = close (pipefd1[1]);
149 status = close (pipefd2[0]);
150 /* Create two pipes for communication */
151 if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
153 mc_global.tty.console_flag = '\0';
154 break;
156 /* Get the console saver running */
157 cons_saver_pid = fork ();
158 if (cons_saver_pid < 0)
160 /* Cannot fork */
161 /* Delete pipes */
162 status = close (pipefd1[1]);
163 status = close (pipefd1[0]);
164 status = close (pipefd2[1]);
165 status = close (pipefd2[0]);
166 mc_global.tty.console_flag = '\0';
168 else if (cons_saver_pid > 0)
170 /* Parent */
171 /* Close the extra pipe ends */
172 status = close (pipefd1[0]);
173 status = close (pipefd2[1]);
174 /* Was the child successful? */
175 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
176 if (mc_global.tty.console_flag == '\0')
178 pid_t ret;
179 status = close (pipefd1[1]);
180 status = close (pipefd2[0]);
181 ret = waitpid (cons_saver_pid, &status, 0);
184 else
186 /* Child */
187 /* Close the extra pipe ends */
188 status = close (pipefd1[1]);
189 status = close (pipefd2[0]);
190 tty_name = ttyname (0);
191 /* Bind the pipe 0 to the standard input */
194 if (dup2 (pipefd1[0], 0) == -1)
195 break;
196 status = close (pipefd1[0]);
197 /* Bind the pipe 1 to the standard output */
198 if (dup2 (pipefd2[1], 1) == -1)
199 break;
201 status = close (pipefd2[1]);
202 /* Bind standard error to /dev/null */
203 status = open ("/dev/null", O_WRONLY);
204 if (dup2 (status, 2) == -1)
205 break;
206 status = close (status);
207 if (tty_name)
209 /* Exec the console save/restore handler */
210 mc_conssaver = mc_build_filename (SAVERDIR, "cons.saver", NULL);
211 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
213 /* Console is not a tty or execl() failed */
215 while (0);
216 mc_global.tty.console_flag = '\0';
217 status = write (1, &mc_global.tty.console_flag, 1);
218 _exit (3);
219 } /* if (cons_saver_pid ...) */
220 break;
222 case CONSOLE_DONE:
223 case CONSOLE_SAVE:
224 case CONSOLE_RESTORE:
225 /* Is tty console? */
226 if (mc_global.tty.console_flag == '\0')
227 return;
228 /* Paranoid: Is the cons.saver still running? */
229 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
231 cons_saver_pid = 0;
232 mc_global.tty.console_flag = '\0';
233 return;
235 /* Send command to the console handler */
236 status = write (pipefd1[1], &action, 1);
237 if (action != CONSOLE_DONE)
239 /* Wait the console handler to do its job */
240 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
242 if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
244 /* We are done -> Let's clean up */
245 pid_t ret;
246 close (pipefd1[1]);
247 close (pipefd2[0]);
248 ret = waitpid (cons_saver_pid, &status, 0);
249 mc_global.tty.console_flag = '\0';
251 break;
252 default:
253 break;
257 #elif defined(__FreeBSD__)
259 /* --------------------------------------------------------------------------------------------- */
261 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
262 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
265 static void
266 console_init (void)
268 if (mc_global.tty.console_flag != '\0')
269 return;
271 screen_info.size = sizeof (screen_info);
272 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
273 return;
275 memset (&screen_shot, 0, sizeof (screen_shot));
276 screen_shot.xsize = screen_info.mv_csz;
277 screen_shot.ysize = screen_info.mv_rsz;
278 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
279 if (screen_shot.buf != NULL)
280 mc_global.tty.console_flag = '\001';
283 /* --------------------------------------------------------------------------------------------- */
285 static void
286 set_attr (unsigned attr)
289 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
290 * to indices for ANSI sequences (red=1, green=2, blue=4).
292 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
293 int bc, tc;
295 tc = attr & 0xF;
296 bc = (attr >> 4) & 0xF;
298 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
299 color_map[tc & 7], color_map[bc & 7]);
302 /* --------------------------------------------------------------------------------------------- */
304 static void
305 console_restore (void)
307 int i, last;
309 if (mc_global.tty.console_flag == '\0')
310 return;
312 cursor_to (0, 0);
314 /* restoring all content up to cursor position */
315 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
316 for (i = 0; i < last; ++i)
318 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
319 putc (screen_shot.buf[i] & 0xFF, stdout);
322 /* restoring cursor color */
323 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
325 fflush (stdout);
328 /* --------------------------------------------------------------------------------------------- */
330 static void
331 console_shutdown (void)
333 if (mc_global.tty.console_flag == '\0')
334 return;
336 g_free (screen_shot.buf);
338 mc_global.tty.console_flag = '\0';
341 /* --------------------------------------------------------------------------------------------- */
343 static void
344 console_save (void)
346 int i;
347 scrmap_t map;
348 scrmap_t revmap;
350 if (mc_global.tty.console_flag == '\0')
351 return;
353 /* screen_info.size is already set in console_init() */
354 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
356 console_shutdown ();
357 return;
360 /* handle console resize */
361 if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
363 console_shutdown ();
364 console_init ();
367 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
369 console_shutdown ();
370 return;
373 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
375 console_shutdown ();
376 return;
379 for (i = 0; i < 256; i++)
381 char *p = memchr (map.scrmap, i, 256);
382 revmap.scrmap[i] = p ? p - map.scrmap : i;
385 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
387 /* *INDENT-OFF* */
388 screen_shot.buf[i] = (screen_shot.buf[i] & 0xff00)
389 | (unsigned char) revmap.scrmap[screen_shot.buf[i] & 0xff];
390 /* *INDENT-ON* */
394 /* --------------------------------------------------------------------------------------------- */
396 static void
397 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
399 int col, line;
400 char c;
402 if (mc_global.tty.console_flag == '\0')
403 return;
405 for (line = begin_line; line <= end_line; line++)
407 tty_gotoyx (starty + line - begin_line, 0);
408 for (col = 0; col < min (COLS, screen_info.mv_csz); col++)
410 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
411 tty_print_char (c);
416 /* --------------------------------------------------------------------------------------------- */
418 static void
419 handle_console_freebsd (console_action_t action)
421 switch (action)
423 case CONSOLE_INIT:
424 console_init ();
425 break;
427 case CONSOLE_DONE:
428 console_shutdown ();
429 break;
431 case CONSOLE_SAVE:
432 console_save ();
433 break;
435 case CONSOLE_RESTORE:
436 console_restore ();
437 break;
438 default:
439 break;
442 #endif /* __FreeBSD__ */
444 /* --------------------------------------------------------------------------------------------- */
445 /*** public functions ****************************************************************************/
446 /* --------------------------------------------------------------------------------------------- */
448 void
449 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
451 tty_set_normal_attrs ();
453 if (look_for_rxvt_extensions ())
455 show_rxvt_contents (starty, begin_line, end_line);
456 return;
458 #ifdef __linux__
459 show_console_contents_linux (starty, begin_line, end_line);
460 #elif defined (__FreeBSD__)
461 show_console_contents_freebsd (starty, begin_line, end_line);
462 #else
463 mc_global.tty.console_flag = '\0';
464 #endif
467 /* --------------------------------------------------------------------------------------------- */
469 void
470 handle_console (console_action_t action)
472 (void) action;
474 if (look_for_rxvt_extensions ())
475 return;
477 #ifdef __linux__
478 handle_console_linux (action);
479 #elif defined (__FreeBSD__)
480 handle_console_freebsd (action);
481 #endif
484 /* --------------------------------------------------------------------------------------------- */