2 Client interface for General purpose Linux console save/restore server
4 Copyright (C) 1994-2024
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
33 #include <sys/types.h>
35 #include <sys/consio.h>
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
41 #include "lib/global.h"
43 #include "lib/unixcompat.h"
44 #include "lib/tty/tty.h"
45 #include "lib/tty/color.h" /* tty_set_normal_attrs */
46 #include "lib/tty/win.h"
47 #include "lib/util.h" /* mc_build_filename() */
49 #include "consaver/cons.saver.h"
51 /*** global variables ****************************************************************************/
54 int cons_saver_pid
= 1;
55 #endif /* __linux__ */
57 /*** file scope macro definitions ****************************************************************/
59 #if defined(__FreeBSD__)
61 #define cursor_to(x, y) \
64 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
67 #endif /* __linux__ */
69 /*** file scope type declarations ****************************************************************/
71 /*** forward declarations (file scope functions) *************************************************/
73 /*** file scope variables ************************************************************************/
76 /* The cons saver can't have a pid of 1, used to prevent bunches of
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 /* --------------------------------------------------------------------------------------------- */
86 /*** file scope functions ************************************************************************/
87 /* --------------------------------------------------------------------------------------------- */
91 show_console_contents_linux (int starty
, unsigned char begin_line
, unsigned char end_line
)
93 unsigned char message
= 0;
94 unsigned short bytes
= 0;
99 if (mc_global
.tty
.console_flag
== '\0')
101 /* Paranoid: Is the cons.saver still running? */
102 if (cons_saver_pid
< 1 || kill (cons_saver_pid
, SIGCONT
))
105 mc_global
.tty
.console_flag
= '\0';
109 /* Send command to the console handler */
110 message
= CONSOLE_CONTENTS
;
111 ret
= write (pipefd1
[1], &message
, 1);
112 /* Check for outdated cons.saver */
113 ret
= read (pipefd2
[0], &message
, 1);
114 if (message
!= CONSOLE_CONTENTS
)
117 /* Send the range of lines that we want */
118 ret
= write (pipefd1
[1], &begin_line
, 1);
119 ret
= write (pipefd1
[1], &end_line
, 1);
120 /* Read the corresponding number of bytes */
121 ret
= read (pipefd2
[0], &bytes
, 2);
123 /* Read the bytes and output them */
124 for (i
= 0; i
< bytes
; i
++)
127 tty_gotoyx (starty
+ (i
/ COLS
), 0);
128 ret
= read (pipefd2
[0], &message
, 1);
129 tty_print_char (message
);
132 /* Read the value of the mc_global.tty.console_flag */
133 ret
= read (pipefd2
[0], &message
, 1);
137 /* --------------------------------------------------------------------------------------------- */
140 handle_console_linux (console_action_t action
)
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';
156 /* Get the console saver running */
157 cons_saver_pid
= fork ();
158 if (cons_saver_pid
< 0)
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)
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')
179 status
= close (pipefd1
[1]);
180 status
= close (pipefd2
[0]);
181 ret
= waitpid (cons_saver_pid
, &status
, 0);
190 /* Close the extra pipe ends */
191 status
= close (pipefd1
[1]);
192 status
= close (pipefd2
[0]);
193 tty_name
= ttyname (0);
194 /* Bind the pipe 0 to the standard input */
199 if (dup2 (pipefd1
[0], STDIN_FILENO
) == -1)
201 status
= close (pipefd1
[0]);
202 /* Bind the pipe 1 to the standard output */
203 if (dup2 (pipefd2
[1], STDOUT_FILENO
) == -1)
206 status
= close (pipefd2
[1]);
207 /* Bind standard error to /dev/null */
208 status
= open ("/dev/null", O_WRONLY
);
211 ok
= dup2 (status
, STDERR_FILENO
) != -1;
212 status
= close (status
);
216 if (tty_name
!= NULL
)
220 /* Exec the console save/restore handler */
221 mc_conssaver
= mc_build_filename (SAVERDIR
, "cons.saver", (char *) NULL
);
222 execl (mc_conssaver
, "cons.saver", tty_name
, (char *) NULL
);
224 /* Console is not a tty or execl() failed */
227 mc_global
.tty
.console_flag
= '\0';
228 status
= write (1, &mc_global
.tty
.console_flag
, 1);
230 } /* if (cons_saver_pid ...) */
235 case CONSOLE_RESTORE
:
236 /* Is tty console? */
237 if (mc_global
.tty
.console_flag
== '\0')
239 /* Paranoid: Is the cons.saver still running? */
240 if (cons_saver_pid
< 1 || kill (cons_saver_pid
, SIGCONT
))
243 mc_global
.tty
.console_flag
= '\0';
246 /* Send command to the console handler */
248 /* Convert enum (i.e. int) to char to write the correct value
249 * (the least byte) regardless of machine endianness. */
250 char act
= (char) action
;
252 status
= write (pipefd1
[1], &act
, 1);
254 if (action
!= CONSOLE_DONE
)
256 /* Wait the console handler to do its job */
257 status
= read (pipefd2
[0], &mc_global
.tty
.console_flag
, 1);
259 if (action
== CONSOLE_DONE
|| mc_global
.tty
.console_flag
== '\0')
261 /* We are done -> Let's clean up */
265 ret
= waitpid (cons_saver_pid
, &status
, 0);
267 mc_global
.tty
.console_flag
= '\0';
275 #elif defined(__FreeBSD__)
277 /* --------------------------------------------------------------------------------------------- */
279 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
280 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
286 if (mc_global
.tty
.console_flag
!= '\0')
289 screen_info
.size
= sizeof (screen_info
);
290 if (ioctl (FD_OUT
, CONS_GETINFO
, &screen_info
) == -1)
293 memset (&screen_shot
, 0, sizeof (screen_shot
));
294 screen_shot
.xsize
= screen_info
.mv_csz
;
295 screen_shot
.ysize
= screen_info
.mv_rsz
;
296 screen_shot
.buf
= g_try_malloc (screen_info
.mv_csz
* screen_info
.mv_rsz
* 2);
297 if (screen_shot
.buf
!= NULL
)
298 mc_global
.tty
.console_flag
= '\001';
301 /* --------------------------------------------------------------------------------------------- */
304 set_attr (unsigned attr
)
307 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
308 * to indices for ANSI sequences (red=1, green=2, blue=4).
310 static const int color_map
[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
314 bc
= (attr
>> 4) & 0xF;
316 printf ("\x1B[%d;%d;3%d;4%dm", (bc
& 8) ? 5 : 25, (tc
& 8) ? 1 : 22,
317 color_map
[tc
& 7], color_map
[bc
& 7]);
320 /* --------------------------------------------------------------------------------------------- */
323 console_restore (void)
327 if (mc_global
.tty
.console_flag
== '\0')
332 /* restoring all content up to cursor position */
333 last
= screen_info
.mv_row
* screen_info
.mv_csz
+ screen_info
.mv_col
;
334 for (i
= 0; i
< last
; ++i
)
336 set_attr ((screen_shot
.buf
[i
] >> 8) & 0xFF);
337 putc (screen_shot
.buf
[i
] & 0xFF, stdout
);
340 /* restoring cursor color */
341 set_attr ((screen_shot
.buf
[last
] >> 8) & 0xFF);
346 /* --------------------------------------------------------------------------------------------- */
349 console_shutdown (void)
351 if (mc_global
.tty
.console_flag
== '\0')
354 g_free (screen_shot
.buf
);
356 mc_global
.tty
.console_flag
= '\0';
359 /* --------------------------------------------------------------------------------------------- */
368 if (mc_global
.tty
.console_flag
== '\0')
371 /* screen_info.size is already set in console_init() */
372 if (ioctl (FD_OUT
, CONS_GETINFO
, &screen_info
) == -1)
378 /* handle console resize */
379 if (screen_info
.mv_csz
!= screen_shot
.xsize
|| screen_info
.mv_rsz
!= screen_shot
.ysize
)
385 if (ioctl (FD_OUT
, CONS_SCRSHOT
, &screen_shot
) == -1)
391 if (ioctl (FD_OUT
, GIO_SCRNMAP
, &map
) == -1)
397 for (i
= 0; i
< 256; i
++)
399 char *p
= memchr (map
.scrmap
, i
, 256);
400 revmap
.scrmap
[i
] = p
? p
- map
.scrmap
: i
;
403 for (i
= 0; i
< screen_shot
.xsize
* screen_shot
.ysize
; i
++)
406 screen_shot
.buf
[i
] = (screen_shot
.buf
[i
] & 0xff00)
407 | (unsigned char) revmap
.scrmap
[screen_shot
.buf
[i
] & 0xff];
412 /* --------------------------------------------------------------------------------------------- */
415 show_console_contents_freebsd (int starty
, unsigned char begin_line
, unsigned char end_line
)
420 if (mc_global
.tty
.console_flag
== '\0')
423 for (line
= begin_line
; line
<= end_line
; line
++)
425 tty_gotoyx (starty
+ line
- begin_line
, 0);
426 for (col
= 0; col
< MIN (COLS
, screen_info
.mv_csz
); col
++)
428 c
= screen_shot
.buf
[line
* screen_info
.mv_csz
+ col
] & 0xFF;
434 /* --------------------------------------------------------------------------------------------- */
437 handle_console_freebsd (console_action_t action
)
453 case CONSOLE_RESTORE
:
460 #endif /* __FreeBSD__ */
462 /* --------------------------------------------------------------------------------------------- */
463 /*** public functions ****************************************************************************/
464 /* --------------------------------------------------------------------------------------------- */
467 show_console_contents (int starty
, unsigned char begin_line
, unsigned char end_line
)
469 tty_set_normal_attrs ();
471 if (look_for_rxvt_extensions ())
473 show_rxvt_contents (starty
, begin_line
, end_line
);
477 show_console_contents_linux (starty
, begin_line
, end_line
);
478 #elif defined (__FreeBSD__)
479 show_console_contents_freebsd (starty
, begin_line
, end_line
);
481 mc_global
.tty
.console_flag
= '\0';
485 /* --------------------------------------------------------------------------------------------- */
488 handle_console (console_action_t action
)
492 if (look_for_rxvt_extensions ())
496 handle_console_linux (action
);
497 #elif defined (__FreeBSD__)
498 handle_console_freebsd (action
);
502 /* --------------------------------------------------------------------------------------------- */