Ticket #4281: fish upload: symbolic link along with its target.
[midnight-commander.git] / src / cons.handler.c
blob7ccb5d0833827552d2de138746fef7011f920dcc
1 /*
2 Client interface for General purpose Linux console save/restore server
4 Copyright (C) 1994-2021
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 <sys/types.h>
34 #ifdef __FreeBSD__
35 #include <sys/consio.h>
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #endif
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 ****************************************************************************/
53 #ifdef __linux__
54 int cons_saver_pid = 1;
55 #endif /* __linux__ */
57 /*** file scope macro definitions ****************************************************************/
59 #if defined(__FreeBSD__)
60 #define FD_OUT 1
61 #define cursor_to(x, y) \
62 do \
63 { \
64 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
65 fflush(stdout); \
66 } while (0)
67 #endif /* __linux__ */
69 /*** file scope type declarations ****************************************************************/
71 /*** file scope variables ************************************************************************/
73 #ifdef __linux__
74 /* The cons saver can't have a pid of 1, used to prevent bunches of
75 * #ifdef linux */
76 static int pipefd1[2] = { -1, -1 };
77 static int pipefd2[2] = { -1, -1 };
78 #elif defined(__FreeBSD__)
79 static struct scrshot screen_shot;
80 static struct vid_info screen_info;
81 #endif /* __linux__ */
83 /*** file scope functions ************************************************************************/
84 /* --------------------------------------------------------------------------------------------- */
86 #ifdef __linux__
87 static void
88 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
90 unsigned char message = 0;
91 unsigned short bytes = 0;
92 int i;
93 ssize_t ret;
95 /* Is tty console? */
96 if (mc_global.tty.console_flag == '\0')
97 return;
98 /* Paranoid: Is the cons.saver still running? */
99 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
101 cons_saver_pid = 0;
102 mc_global.tty.console_flag = '\0';
103 return;
106 /* Send command to the console handler */
107 message = CONSOLE_CONTENTS;
108 ret = write (pipefd1[1], &message, 1);
109 /* Check for outdated cons.saver */
110 ret = read (pipefd2[0], &message, 1);
111 if (message != CONSOLE_CONTENTS)
112 return;
114 /* Send the range of lines that we want */
115 ret = write (pipefd1[1], &begin_line, 1);
116 ret = write (pipefd1[1], &end_line, 1);
117 /* Read the corresponding number of bytes */
118 ret = read (pipefd2[0], &bytes, 2);
120 /* Read the bytes and output them */
121 for (i = 0; i < bytes; i++)
123 if ((i % COLS) == 0)
124 tty_gotoyx (starty + (i / COLS), 0);
125 ret = read (pipefd2[0], &message, 1);
126 tty_print_char (message);
129 /* Read the value of the mc_global.tty.console_flag */
130 ret = read (pipefd2[0], &message, 1);
131 (void) ret;
134 /* --------------------------------------------------------------------------------------------- */
136 static void
137 handle_console_linux (console_action_t action)
139 int status;
141 switch (action)
143 case CONSOLE_INIT:
144 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
145 status = close (pipefd1[1]);
146 status = close (pipefd2[0]);
147 /* Create two pipes for communication */
148 if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
150 mc_global.tty.console_flag = '\0';
151 break;
153 /* Get the console saver running */
154 cons_saver_pid = fork ();
155 if (cons_saver_pid < 0)
157 /* Cannot fork */
158 /* Delete pipes */
159 status = close (pipefd1[1]);
160 status = close (pipefd1[0]);
161 status = close (pipefd2[1]);
162 status = close (pipefd2[0]);
163 mc_global.tty.console_flag = '\0';
165 else if (cons_saver_pid > 0)
167 /* Parent */
168 /* Close the extra pipe ends */
169 status = close (pipefd1[0]);
170 status = close (pipefd2[1]);
171 /* Was the child successful? */
172 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
173 if (mc_global.tty.console_flag == '\0')
175 pid_t ret;
176 status = close (pipefd1[1]);
177 status = close (pipefd2[0]);
178 ret = waitpid (cons_saver_pid, &status, 0);
179 (void) ret;
182 else
184 /* Child */
185 char *tty_name;
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 gboolean ok;
196 if (dup2 (pipefd1[0], STDIN_FILENO) == -1)
197 break;
198 status = close (pipefd1[0]);
199 /* Bind the pipe 1 to the standard output */
200 if (dup2 (pipefd2[1], STDOUT_FILENO) == -1)
201 break;
203 status = close (pipefd2[1]);
204 /* Bind standard error to /dev/null */
205 status = open ("/dev/null", O_WRONLY);
206 if (status == -1)
207 break;
208 ok = dup2 (status, STDERR_FILENO) != -1;
209 status = close (status);
210 if (!ok)
211 break;
213 if (tty_name != NULL)
215 char *mc_conssaver;
217 /* Exec the console save/restore handler */
218 mc_conssaver = mc_build_filename (SAVERDIR, "cons.saver", (char *) NULL);
219 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
221 /* Console is not a tty or execl() failed */
223 while (0);
224 mc_global.tty.console_flag = '\0';
225 status = write (1, &mc_global.tty.console_flag, 1);
226 my_exit (3);
227 } /* if (cons_saver_pid ...) */
228 break;
230 case CONSOLE_DONE:
231 case CONSOLE_SAVE:
232 case CONSOLE_RESTORE:
233 /* Is tty console? */
234 if (mc_global.tty.console_flag == '\0')
235 return;
236 /* Paranoid: Is the cons.saver still running? */
237 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
239 cons_saver_pid = 0;
240 mc_global.tty.console_flag = '\0';
241 return;
243 /* Send command to the console handler */
244 status = write (pipefd1[1], &action, 1);
245 if (action != CONSOLE_DONE)
247 /* Wait the console handler to do its job */
248 status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
250 if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
252 /* We are done -> Let's clean up */
253 pid_t ret;
254 close (pipefd1[1]);
255 close (pipefd2[0]);
256 ret = waitpid (cons_saver_pid, &status, 0);
257 (void) ret;
258 mc_global.tty.console_flag = '\0';
260 break;
261 default:
262 break;
266 #elif defined(__FreeBSD__)
268 /* --------------------------------------------------------------------------------------------- */
270 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
271 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
274 static void
275 console_init (void)
277 if (mc_global.tty.console_flag != '\0')
278 return;
280 screen_info.size = sizeof (screen_info);
281 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
282 return;
284 memset (&screen_shot, 0, sizeof (screen_shot));
285 screen_shot.xsize = screen_info.mv_csz;
286 screen_shot.ysize = screen_info.mv_rsz;
287 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
288 if (screen_shot.buf != NULL)
289 mc_global.tty.console_flag = '\001';
292 /* --------------------------------------------------------------------------------------------- */
294 static void
295 set_attr (unsigned attr)
298 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
299 * to indices for ANSI sequences (red=1, green=2, blue=4).
301 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
302 int bc, tc;
304 tc = attr & 0xF;
305 bc = (attr >> 4) & 0xF;
307 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
308 color_map[tc & 7], color_map[bc & 7]);
311 /* --------------------------------------------------------------------------------------------- */
313 static void
314 console_restore (void)
316 int i, last;
318 if (mc_global.tty.console_flag == '\0')
319 return;
321 cursor_to (0, 0);
323 /* restoring all content up to cursor position */
324 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
325 for (i = 0; i < last; ++i)
327 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
328 putc (screen_shot.buf[i] & 0xFF, stdout);
331 /* restoring cursor color */
332 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
334 fflush (stdout);
337 /* --------------------------------------------------------------------------------------------- */
339 static void
340 console_shutdown (void)
342 if (mc_global.tty.console_flag == '\0')
343 return;
345 g_free (screen_shot.buf);
347 mc_global.tty.console_flag = '\0';
350 /* --------------------------------------------------------------------------------------------- */
352 static void
353 console_save (void)
355 int i;
356 scrmap_t map;
357 scrmap_t revmap;
359 if (mc_global.tty.console_flag == '\0')
360 return;
362 /* screen_info.size is already set in console_init() */
363 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
365 console_shutdown ();
366 return;
369 /* handle console resize */
370 if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
372 console_shutdown ();
373 console_init ();
376 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
378 console_shutdown ();
379 return;
382 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
384 console_shutdown ();
385 return;
388 for (i = 0; i < 256; i++)
390 char *p = memchr (map.scrmap, i, 256);
391 revmap.scrmap[i] = p ? p - map.scrmap : i;
394 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
396 /* *INDENT-OFF* */
397 screen_shot.buf[i] = (screen_shot.buf[i] & 0xff00)
398 | (unsigned char) revmap.scrmap[screen_shot.buf[i] & 0xff];
399 /* *INDENT-ON* */
403 /* --------------------------------------------------------------------------------------------- */
405 static void
406 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
408 int col, line;
409 char c;
411 if (mc_global.tty.console_flag == '\0')
412 return;
414 for (line = begin_line; line <= end_line; line++)
416 tty_gotoyx (starty + line - begin_line, 0);
417 for (col = 0; col < MIN (COLS, screen_info.mv_csz); col++)
419 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
420 tty_print_char (c);
425 /* --------------------------------------------------------------------------------------------- */
427 static void
428 handle_console_freebsd (console_action_t action)
430 switch (action)
432 case CONSOLE_INIT:
433 console_init ();
434 break;
436 case CONSOLE_DONE:
437 console_shutdown ();
438 break;
440 case CONSOLE_SAVE:
441 console_save ();
442 break;
444 case CONSOLE_RESTORE:
445 console_restore ();
446 break;
447 default:
448 break;
451 #endif /* __FreeBSD__ */
453 /* --------------------------------------------------------------------------------------------- */
454 /*** public functions ****************************************************************************/
455 /* --------------------------------------------------------------------------------------------- */
457 void
458 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
460 tty_set_normal_attrs ();
462 if (look_for_rxvt_extensions ())
464 show_rxvt_contents (starty, begin_line, end_line);
465 return;
467 #ifdef __linux__
468 show_console_contents_linux (starty, begin_line, end_line);
469 #elif defined (__FreeBSD__)
470 show_console_contents_freebsd (starty, begin_line, end_line);
471 #else
472 mc_global.tty.console_flag = '\0';
473 #endif
476 /* --------------------------------------------------------------------------------------------- */
478 void
479 handle_console (console_action_t action)
481 (void) action;
483 if (look_for_rxvt_extensions ())
484 return;
486 #ifdef __linux__
487 handle_console_linux (action);
488 #elif defined (__FreeBSD__)
489 handle_console_freebsd (action);
490 #endif
493 /* --------------------------------------------------------------------------------------------- */