replaced buggy concat_dir_and_file() by mhl_str_dir_plus_file()
[free-mc.git] / src / cons.handler.c
blob1fe35b0b3fd5a3c904b7cf9e6e0f4d4e717a501d
1 /* Client interface for General purpose Linux console save/restore server
2 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19 #include <config.h>
21 #include <signal.h>
22 #include <stdio.h>
24 #include <sys/types.h>
25 #ifdef __FreeBSD__
26 # include <sys/consio.h>
27 # include <sys/ioctl.h>
28 #endif
29 #include <unistd.h>
31 #include <mhl/string.h>
33 #include "global.h"
34 #include "tty.h"
35 #include "cons.saver.h"
37 signed char console_flag = 0;
39 #ifdef __linux__
41 /* The cons saver can't have a pid of 1, used to prevent bunches of
42 * #ifdef linux */
44 int cons_saver_pid = 1;
45 static int pipefd1[2] = { -1, -1 };
46 static int pipefd2[2] = { -1, -1 };
48 static void
49 show_console_contents_linux (int starty, unsigned char begin_line,
50 unsigned char end_line)
52 unsigned char message = 0;
53 unsigned short bytes = 0;
54 int i;
56 /* Is tty console? */
57 if (!console_flag)
58 return;
59 /* Paranoid: Is the cons.saver still running? */
60 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
61 cons_saver_pid = 0;
62 console_flag = 0;
63 return;
66 /* Send command to the console handler */
67 message = CONSOLE_CONTENTS;
68 write (pipefd1[1], &message, 1);
69 /* Check for outdated cons.saver */
70 read (pipefd2[0], &message, 1);
71 if (message != CONSOLE_CONTENTS)
72 return;
74 /* Send the range of lines that we want */
75 write (pipefd1[1], &begin_line, 1);
76 write (pipefd1[1], &end_line, 1);
77 /* Read the corresponding number of bytes */
78 read (pipefd2[0], &bytes, 2);
80 /* Read the bytes and output them */
81 for (i = 0; i < bytes; i++) {
82 if ((i % COLS) == 0)
83 move (starty + (i / COLS), 0);
84 read (pipefd2[0], &message, 1);
85 addch (message);
88 /* Read the value of the console_flag */
89 read (pipefd2[0], &message, 1);
92 static void
93 handle_console_linux (unsigned char action)
95 char *tty_name;
96 char *mc_conssaver;
97 int status;
99 switch (action) {
100 case CONSOLE_INIT:
101 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
102 close (pipefd1[1]);
103 close (pipefd2[0]);
104 /* Create two pipes for communication */
105 pipe (pipefd1);
106 pipe (pipefd2);
107 /* Get the console saver running */
108 cons_saver_pid = fork ();
109 if (cons_saver_pid < 0) {
110 /* Cannot fork */
111 /* Delete pipes */
112 close (pipefd1[1]);
113 close (pipefd1[0]);
114 close (pipefd2[1]);
115 close (pipefd2[0]);
116 console_flag = 0;
117 } else if (cons_saver_pid > 0) {
118 /* Parent */
119 /* Close the extra pipe ends */
120 close (pipefd1[0]);
121 close (pipefd2[1]);
122 /* Was the child successful? */
123 read (pipefd2[0], &console_flag, 1);
124 if (!console_flag) {
125 close (pipefd1[1]);
126 close (pipefd2[0]);
127 waitpid (cons_saver_pid, &status, 0);
129 } else {
130 /* Child */
131 /* Close the extra pipe ends */
132 close (pipefd1[1]);
133 close (pipefd2[0]);
134 tty_name = ttyname (0);
135 /* Bind the pipe 0 to the standard input */
136 close (0);
137 dup (pipefd1[0]);
138 close (pipefd1[0]);
139 /* Bind the pipe 1 to the standard output */
140 close (1);
141 dup (pipefd2[1]);
142 close (pipefd2[1]);
143 /* Bind standard error to /dev/null */
144 close (2);
145 open ("/dev/null", O_WRONLY);
146 if (tty_name) {
147 /* Exec the console save/restore handler */
148 mc_conssaver = mhl_str_dir_plus_file (SAVERDIR, "cons.saver");
149 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
151 /* Console is not a tty or execl() failed */
152 console_flag = 0;
153 write (1, &console_flag, 1);
154 _exit (3);
155 } /* if (cons_saver_pid ...) */
156 break;
158 case CONSOLE_DONE:
159 case CONSOLE_SAVE:
160 case CONSOLE_RESTORE:
161 /* Is tty console? */
162 if (!console_flag)
163 return;
164 /* Paranoid: Is the cons.saver still running? */
165 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
166 cons_saver_pid = 0;
167 console_flag = 0;
168 return;
170 /* Send command to the console handler */
171 write (pipefd1[1], &action, 1);
172 if (action != CONSOLE_DONE) {
173 /* Wait the console handler to do its job */
174 read (pipefd2[0], &console_flag, 1);
176 if (action == CONSOLE_DONE || !console_flag) {
177 /* We are done -> Let's clean up */
178 close (pipefd1[1]);
179 close (pipefd2[0]);
180 waitpid (cons_saver_pid, &status, 0);
181 console_flag = 0;
183 break;
187 #elif defined(__FreeBSD__)
190 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
191 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
194 #define FD_OUT 1
196 static struct scrshot screen_shot;
197 static struct vid_info screen_info;
199 static void
200 console_init (void)
202 if (console_flag)
203 return;
205 screen_info.size = sizeof (screen_info);
206 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
207 return;
209 memset (&screen_shot, 0, sizeof (screen_shot));
210 screen_shot.xsize = screen_info.mv_csz;
211 screen_shot.ysize = screen_info.mv_rsz;
212 if ((screen_shot.buf =
213 g_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2)) == NULL)
214 return;
216 console_flag = 1;
219 static void
220 set_attr (unsigned attr)
223 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
224 * to indices for ANSI sequences (red=1, green=2, blue=4).
226 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
227 int bc, tc;
229 tc = attr & 0xF;
230 bc = (attr >> 4) & 0xF;
232 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
233 color_map[tc & 7], color_map[bc & 7]);
236 #define cursor_to(x, y) do { \
237 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
238 fflush(stdout); \
239 } while (0)
241 static void
242 console_restore (void)
244 int i, last;
246 if (!console_flag)
247 return;
249 cursor_to (0, 0);
251 /* restoring all content up to cursor position */
252 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
253 for (i = 0; i < last; ++i) {
254 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
255 putc (screen_shot.buf[i] & 0xFF, stdout);
258 /* restoring cursor color */
259 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
261 fflush (stdout);
264 static void
265 console_shutdown (void)
267 if (!console_flag)
268 return;
270 g_free (screen_shot.buf);
272 console_flag = 0;
275 static void
276 console_save (void)
278 int i;
279 scrmap_t map;
280 scrmap_t revmap;
282 if (!console_flag)
283 return;
285 /* screen_info.size is already set in console_init() */
286 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1) {
287 console_shutdown ();
288 return;
291 /* handle console resize */
292 if (screen_info.mv_csz != screen_shot.xsize
293 || screen_info.mv_rsz != screen_shot.ysize) {
294 console_shutdown ();
295 console_init ();
298 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1) {
299 console_shutdown ();
300 return;
303 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1) {
304 console_shutdown ();
305 return;
308 for (i = 0; i < 256; i++) {
309 char *p = memchr (map.scrmap, i, 256);
310 revmap.scrmap[i] = p ? p - map.scrmap : i;
313 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++) {
314 screen_shot.buf[i] =
315 (screen_shot.buf[i] & 0xff00) | (unsigned char) revmap.
316 scrmap[screen_shot.buf[i] & 0xff];
320 static void
321 show_console_contents_freebsd (int starty, unsigned char begin_line,
322 unsigned char end_line)
324 int col, line;
325 char c;
327 if (!console_flag)
328 return;
330 for (line = begin_line; line <= end_line; line++) {
331 move (starty + line - begin_line, 0);
332 for (col = 0; col < min (COLS, screen_info.mv_csz); col++) {
333 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
334 addch (c);
339 static void
340 handle_console_freebsd (unsigned char action)
342 switch (action) {
343 case CONSOLE_INIT:
344 console_init ();
345 break;
347 case CONSOLE_DONE:
348 console_shutdown ();
349 break;
351 case CONSOLE_SAVE:
352 console_save ();
353 break;
355 case CONSOLE_RESTORE:
356 console_restore ();
357 break;
360 #endif /* __FreeBSD__ */
362 void
363 show_console_contents (int starty, unsigned char begin_line,
364 unsigned char end_line)
366 standend ();
368 if (look_for_rxvt_extensions ()) {
369 show_rxvt_contents (starty, begin_line, end_line);
370 return;
372 #ifdef __linux__
373 show_console_contents_linux (starty, begin_line, end_line);
374 #elif defined (__FreeBSD__)
375 show_console_contents_freebsd (starty, begin_line, end_line);
376 #else
377 console_flag = 0;
378 #endif
381 void
382 handle_console (unsigned char action)
384 (void) action;
386 if (look_for_rxvt_extensions ())
387 return;
389 #ifdef __linux__
390 handle_console_linux (action);
391 #elif defined (__FreeBSD__)
392 handle_console_freebsd (action);
393 #endif