Changes into src directory:
[midnight-commander.git] / src / cons.handler.c
blob8887b2ef7bee9d7f55a79cade4ce236d54f1ffd4
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 /** \file cons.handler.c
20 * \brief Source: client %interface for General purpose Linux console save/restore server
23 #include <config.h>
25 #include <stdlib.h>
26 #include <sys/wait.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #ifdef __FreeBSD__
32 # include <sys/consio.h>
33 # include <sys/ioctl.h>
34 #endif
35 #include <unistd.h>
37 #include "lib/global.h"
39 #include "lib/tty/tty.h"
40 #include "lib/skin.h" /* tty_set_normal_attrs */
41 #include "lib/tty/win.h"
43 #include "consaver/cons.saver.h"
45 signed char console_flag = 0;
47 #ifdef __linux__
49 /* The cons saver can't have a pid of 1, used to prevent bunches of
50 * #ifdef linux */
52 int cons_saver_pid = 1;
53 static int pipefd1[2] = { -1, -1 };
54 static int pipefd2[2] = { -1, -1 };
56 static void
57 show_console_contents_linux (int starty, unsigned char begin_line,
58 unsigned char end_line)
60 unsigned char message = 0;
61 unsigned short bytes = 0;
62 int i;
63 ssize_t ret;
65 /* Is tty console? */
66 if (!console_flag)
67 return;
68 /* Paranoid: Is the cons.saver still running? */
69 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
70 cons_saver_pid = 0;
71 console_flag = 0;
72 return;
75 /* Send command to the console handler */
76 message = CONSOLE_CONTENTS;
77 ret = write (pipefd1[1], &message, 1);
78 /* Check for outdated cons.saver */
79 ret = read (pipefd2[0], &message, 1);
80 if (message != CONSOLE_CONTENTS)
81 return;
83 /* Send the range of lines that we want */
84 ret = write (pipefd1[1], &begin_line, 1);
85 ret = write (pipefd1[1], &end_line, 1);
86 /* Read the corresponding number of bytes */
87 ret = read (pipefd2[0], &bytes, 2);
89 /* Read the bytes and output them */
90 for (i = 0; i < bytes; i++) {
91 if ((i % COLS) == 0)
92 tty_gotoyx (starty + (i / COLS), 0);
93 ret = read (pipefd2[0], &message, 1);
94 tty_print_char (message);
97 /* Read the value of the console_flag */
98 ret = read (pipefd2[0], &message, 1);
101 static void
102 handle_console_linux (unsigned char action)
104 char *tty_name;
105 char *mc_conssaver;
106 int status;
108 switch (action) {
109 case CONSOLE_INIT:
110 /* Close old pipe ends in case it is the 2nd time we run cons.saver */
111 status = close (pipefd1[1]);
112 status = close (pipefd2[0]);
113 /* Create two pipes for communication */
114 if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
116 console_flag = 0;
117 break;
119 /* Get the console saver running */
120 cons_saver_pid = fork ();
121 if (cons_saver_pid < 0) {
122 /* Cannot fork */
123 /* Delete pipes */
124 status = close (pipefd1[1]);
125 status = close (pipefd1[0]);
126 status = close (pipefd2[1]);
127 status = close (pipefd2[0]);
128 console_flag = 0;
129 } else if (cons_saver_pid > 0) {
130 /* Parent */
131 /* Close the extra pipe ends */
132 status = close (pipefd1[0]);
133 status = close (pipefd2[1]);
134 /* Was the child successful? */
135 status = read (pipefd2[0], &console_flag, 1);
136 if (!console_flag) {
137 pid_t ret;
138 status = close (pipefd1[1]);
139 status = close (pipefd2[0]);
140 ret = waitpid (cons_saver_pid, &status, 0);
142 } else {
143 /* Child */
144 /* Close the extra pipe ends */
145 status = close (pipefd1[1]);
146 status = close (pipefd2[0]);
147 tty_name = ttyname (0);
148 /* Bind the pipe 0 to the standard input */
149 do {
150 if ( dup2 (pipefd1[0], 0) == -1)
151 break;
152 status = close (pipefd1[0]);
153 /* Bind the pipe 1 to the standard output */
154 if ( dup2 (pipefd2[1], 1) == -1)
155 break;
157 status = close (pipefd2[1]);
158 /* Bind standard error to /dev/null */
159 status = open ("/dev/null", O_WRONLY);
160 if ( dup2(status, 2) == -1)
161 break;
162 status = close (status);
163 if (tty_name) {
164 /* Exec the console save/restore handler */
165 mc_conssaver = concat_dir_and_file (SAVERDIR, "cons.saver");
166 execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
168 /* Console is not a tty or execl() failed */
169 } while (0);
170 console_flag = 0;
171 status = write (1, &console_flag, 1);
172 _exit (3);
173 } /* if (cons_saver_pid ...) */
174 break;
176 case CONSOLE_DONE:
177 case CONSOLE_SAVE:
178 case CONSOLE_RESTORE:
179 /* Is tty console? */
180 if (!console_flag)
181 return;
182 /* Paranoid: Is the cons.saver still running? */
183 if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)) {
184 cons_saver_pid = 0;
185 console_flag = 0;
186 return;
188 /* Send command to the console handler */
189 status = write (pipefd1[1], &action, 1);
190 if (action != CONSOLE_DONE) {
191 /* Wait the console handler to do its job */
192 status = read (pipefd2[0], &console_flag, 1);
194 if (action == CONSOLE_DONE || !console_flag) {
195 /* We are done -> Let's clean up */
196 pid_t ret;
197 close (pipefd1[1]);
198 close (pipefd2[0]);
199 ret = waitpid (cons_saver_pid, &status, 0);
200 console_flag = 0;
202 break;
206 #elif defined(__FreeBSD__)
209 * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
210 * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
213 #define FD_OUT 1
215 static struct scrshot screen_shot;
216 static struct vid_info screen_info;
218 static void
219 console_init (void)
221 if (console_flag)
222 return;
224 screen_info.size = sizeof (screen_info);
225 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
226 return;
228 memset (&screen_shot, 0, sizeof (screen_shot));
229 screen_shot.xsize = screen_info.mv_csz;
230 screen_shot.ysize = screen_info.mv_rsz;
231 screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
232 if (screen_shot.buf != NULL)
233 console_flag = 1;
236 static void
237 set_attr (unsigned attr)
240 * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
241 * to indices for ANSI sequences (red=1, green=2, blue=4).
243 static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
244 int bc, tc;
246 tc = attr & 0xF;
247 bc = (attr >> 4) & 0xF;
249 printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
250 color_map[tc & 7], color_map[bc & 7]);
253 #define cursor_to(x, y) do { \
254 printf("\x1B[%d;%df", (y) + 1, (x) + 1); \
255 fflush(stdout); \
256 } while (0)
258 static void
259 console_restore (void)
261 int i, last;
263 if (!console_flag)
264 return;
266 cursor_to (0, 0);
268 /* restoring all content up to cursor position */
269 last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
270 for (i = 0; i < last; ++i) {
271 set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
272 putc (screen_shot.buf[i] & 0xFF, stdout);
275 /* restoring cursor color */
276 set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
278 fflush (stdout);
281 static void
282 console_shutdown (void)
284 if (!console_flag)
285 return;
287 g_free (screen_shot.buf);
289 console_flag = 0;
292 static void
293 console_save (void)
295 int i;
296 scrmap_t map;
297 scrmap_t revmap;
299 if (!console_flag)
300 return;
302 /* screen_info.size is already set in console_init() */
303 if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1) {
304 console_shutdown ();
305 return;
308 /* handle console resize */
309 if (screen_info.mv_csz != screen_shot.xsize
310 || screen_info.mv_rsz != screen_shot.ysize) {
311 console_shutdown ();
312 console_init ();
315 if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1) {
316 console_shutdown ();
317 return;
320 if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1) {
321 console_shutdown ();
322 return;
325 for (i = 0; i < 256; i++) {
326 char *p = memchr (map.scrmap, i, 256);
327 revmap.scrmap[i] = p ? p - map.scrmap : i;
330 for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++) {
331 screen_shot.buf[i] =
332 (screen_shot.buf[i] & 0xff00) | (unsigned char) revmap.
333 scrmap[screen_shot.buf[i] & 0xff];
337 static void
338 show_console_contents_freebsd (int starty, unsigned char begin_line,
339 unsigned char end_line)
341 int col, line;
342 char c;
344 if (!console_flag)
345 return;
347 for (line = begin_line; line <= end_line; line++) {
348 tty_gotoyx (starty + line - begin_line, 0);
349 for (col = 0; col < min (COLS, screen_info.mv_csz); col++) {
350 c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
351 tty_print_char (c);
356 static void
357 handle_console_freebsd (unsigned char action)
359 switch (action) {
360 case CONSOLE_INIT:
361 console_init ();
362 break;
364 case CONSOLE_DONE:
365 console_shutdown ();
366 break;
368 case CONSOLE_SAVE:
369 console_save ();
370 break;
372 case CONSOLE_RESTORE:
373 console_restore ();
374 break;
377 #endif /* __FreeBSD__ */
379 void
380 show_console_contents (int starty, unsigned char begin_line,
381 unsigned char end_line)
383 tty_set_normal_attrs ();
385 if (look_for_rxvt_extensions ()) {
386 show_rxvt_contents (starty, begin_line, end_line);
387 return;
389 #ifdef __linux__
390 show_console_contents_linux (starty, begin_line, end_line);
391 #elif defined (__FreeBSD__)
392 show_console_contents_freebsd (starty, begin_line, end_line);
393 #else
394 console_flag = 0;
395 #endif
398 void
399 handle_console (unsigned char action)
401 (void) action;
403 if (look_for_rxvt_extensions ())
404 return;
406 #ifdef __linux__
407 handle_console_linux (action);
408 #elif defined (__FreeBSD__)
409 handle_console_freebsd (action);
410 #endif