root/src/cons.handler.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. show_console_contents_linux
  2. handle_console_linux
  3. console_init
  4. set_attr
  5. console_restore
  6. console_shutdown
  7. console_save
  8. show_console_contents_freebsd
  9. handle_console_freebsd
  10. show_console_contents
  11. handle_console

   1 /*
   2    Client interface for General purpose Linux console save/restore server
   3 
   4    Copyright (C) 1994-2019
   5    Free Software Foundation, Inc.
   6 
   7    This file is part of the Midnight Commander.
   8 
   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.
  13 
  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.
  18 
  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/>.
  21  */
  22 
  23 /** \file cons.handler.c
  24  *  \brief Source: client %interface for General purpose Linux console save/restore server
  25  */
  26 
  27 #include <config.h>
  28 
  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
  40 
  41 #include "lib/global.h"
  42 
  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() */
  48 
  49 #include "consaver/cons.saver.h"
  50 
  51 /*** global variables ****************************************************************************/
  52 
  53 #ifdef __linux__
  54 int cons_saver_pid = 1;
  55 #endif /* __linux__ */
  56 
  57 /*** file scope macro definitions ****************************************************************/
  58 
  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__ */
  68 
  69 /*** file scope type declarations ****************************************************************/
  70 
  71 /*** file scope variables ************************************************************************/
  72 
  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__ */
  82 
  83 /*** file scope functions ************************************************************************/
  84 /* --------------------------------------------------------------------------------------------- */
  85 
  86 #ifdef __linux__
  87 static void
  88 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
  89 {
  90     unsigned char message = 0;
  91     unsigned short bytes = 0;
  92     int i;
  93     ssize_t ret;
  94 
  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))
 100     {
 101         cons_saver_pid = 0;
 102         mc_global.tty.console_flag = '\0';
 103         return;
 104     }
 105 
 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;
 113 
 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);
 119 
 120     /* Read the bytes and output them */
 121     for (i = 0; i < bytes; i++)
 122     {
 123         if ((i % COLS) == 0)
 124             tty_gotoyx (starty + (i / COLS), 0);
 125         ret = read (pipefd2[0], &message, 1);
 126         tty_print_char (message);
 127     }
 128 
 129     /* Read the value of the mc_global.tty.console_flag */
 130     ret = read (pipefd2[0], &message, 1);
 131     (void) ret;
 132 }
 133 
 134 /* --------------------------------------------------------------------------------------------- */
 135 
 136 static void
 137 handle_console_linux (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 138 {
 139     int status;
 140 
 141     switch (action)
 142     {
 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)))
 149         {
 150             mc_global.tty.console_flag = '\0';
 151             break;
 152         }
 153         /* Get the console saver running */
 154         cons_saver_pid = fork ();
 155         if (cons_saver_pid < 0)
 156         {
 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';
 164         }
 165         else if (cons_saver_pid > 0)
 166         {
 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')
 174             {
 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;
 180             }
 181         }
 182         else
 183         {
 184             /* Child */
 185             char *tty_name;
 186 
 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 */
 192             do
 193             {
 194                 if (dup2 (pipefd1[0], STDIN_FILENO) == -1)
 195                     break;
 196                 status = close (pipefd1[0]);
 197                 /* Bind the pipe 1 to the standard output */
 198                 if (dup2 (pipefd2[1], STDOUT_FILENO) == -1)
 199                     break;
 200 
 201                 status = close (pipefd2[1]);
 202                 /* Bind standard error to /dev/null */
 203                 status = open ("/dev/null", O_WRONLY);
 204                 if (dup2 (status, STDERR_FILENO) == -1)
 205                     break;
 206                 status = close (status);
 207                 if (tty_name != NULL)
 208                 {
 209                     char *mc_conssaver;
 210 
 211                     /* Exec the console save/restore handler */
 212                     mc_conssaver = mc_build_filename (SAVERDIR, "cons.saver", (char *) NULL);
 213                     execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
 214                 }
 215                 /* Console is not a tty or execl() failed */
 216             }
 217             while (0);
 218             mc_global.tty.console_flag = '\0';
 219             status = write (1, &mc_global.tty.console_flag, 1);
 220             my_exit (3);
 221         }                       /* if (cons_saver_pid ...) */
 222         break;
 223 
 224     case CONSOLE_DONE:
 225     case CONSOLE_SAVE:
 226     case CONSOLE_RESTORE:
 227         /* Is tty console? */
 228         if (mc_global.tty.console_flag == '\0')
 229             return;
 230         /* Paranoid: Is the cons.saver still running? */
 231         if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
 232         {
 233             cons_saver_pid = 0;
 234             mc_global.tty.console_flag = '\0';
 235             return;
 236         }
 237         /* Send command to the console handler */
 238         status = write (pipefd1[1], &action, 1);
 239         if (action != CONSOLE_DONE)
 240         {
 241             /* Wait the console handler to do its job */
 242             status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
 243         }
 244         if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
 245         {
 246             /* We are done -> Let's clean up */
 247             pid_t ret;
 248             close (pipefd1[1]);
 249             close (pipefd2[0]);
 250             ret = waitpid (cons_saver_pid, &status, 0);
 251             (void) ret;
 252             mc_global.tty.console_flag = '\0';
 253         }
 254         break;
 255     default:
 256         break;
 257     }
 258 }
 259 
 260 #elif defined(__FreeBSD__)
 261 
 262 /* --------------------------------------------------------------------------------------------- */
 263 /**
 264  * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
 265  * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
 266  */
 267 
 268 static void
 269 console_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 270 {
 271     if (mc_global.tty.console_flag != '\0')
 272         return;
 273 
 274     screen_info.size = sizeof (screen_info);
 275     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 276         return;
 277 
 278     memset (&screen_shot, 0, sizeof (screen_shot));
 279     screen_shot.xsize = screen_info.mv_csz;
 280     screen_shot.ysize = screen_info.mv_rsz;
 281     screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
 282     if (screen_shot.buf != NULL)
 283         mc_global.tty.console_flag = '\001';
 284 }
 285 
 286 /* --------------------------------------------------------------------------------------------- */
 287 
 288 static void
 289 set_attr (unsigned attr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 290 {
 291     /*
 292      * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
 293      * to indices for ANSI sequences (red=1, green=2, blue=4).
 294      */
 295     static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 296     int bc, tc;
 297 
 298     tc = attr & 0xF;
 299     bc = (attr >> 4) & 0xF;
 300 
 301     printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
 302             color_map[tc & 7], color_map[bc & 7]);
 303 }
 304 
 305 /* --------------------------------------------------------------------------------------------- */
 306 
 307 static void
 308 console_restore (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 309 {
 310     int i, last;
 311 
 312     if (mc_global.tty.console_flag == '\0')
 313         return;
 314 
 315     cursor_to (0, 0);
 316 
 317     /* restoring all content up to cursor position */
 318     last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
 319     for (i = 0; i < last; ++i)
 320     {
 321         set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
 322         putc (screen_shot.buf[i] & 0xFF, stdout);
 323     }
 324 
 325     /* restoring cursor color */
 326     set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
 327 
 328     fflush (stdout);
 329 }
 330 
 331 /* --------------------------------------------------------------------------------------------- */
 332 
 333 static void
 334 console_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 335 {
 336     if (mc_global.tty.console_flag == '\0')
 337         return;
 338 
 339     g_free (screen_shot.buf);
 340 
 341     mc_global.tty.console_flag = '\0';
 342 }
 343 
 344 /* --------------------------------------------------------------------------------------------- */
 345 
 346 static void
 347 console_save (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 348 {
 349     int i;
 350     scrmap_t map;
 351     scrmap_t revmap;
 352 
 353     if (mc_global.tty.console_flag == '\0')
 354         return;
 355 
 356     /* screen_info.size is already set in console_init() */
 357     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 358     {
 359         console_shutdown ();
 360         return;
 361     }
 362 
 363     /* handle console resize */
 364     if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
 365     {
 366         console_shutdown ();
 367         console_init ();
 368     }
 369 
 370     if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
 371     {
 372         console_shutdown ();
 373         return;
 374     }
 375 
 376     if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
 377     {
 378         console_shutdown ();
 379         return;
 380     }
 381 
 382     for (i = 0; i < 256; i++)
 383     {
 384         char *p = memchr (map.scrmap, i, 256);
 385         revmap.scrmap[i] = p ? p - map.scrmap : i;
 386     }
 387 
 388     for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
 389     {
 390         /* *INDENT-OFF* */
 391         screen_shot.buf[i] = (screen_shot.buf[i] & 0xff00) 
 392             | (unsigned char) revmap.scrmap[screen_shot.buf[i] & 0xff];
 393         /* *INDENT-ON* */
 394     }
 395 }
 396 
 397 /* --------------------------------------------------------------------------------------------- */
 398 
 399 static void
 400 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 401 {
 402     int col, line;
 403     char c;
 404 
 405     if (mc_global.tty.console_flag == '\0')
 406         return;
 407 
 408     for (line = begin_line; line <= end_line; line++)
 409     {
 410         tty_gotoyx (starty + line - begin_line, 0);
 411         for (col = 0; col < MIN (COLS, screen_info.mv_csz); col++)
 412         {
 413             c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
 414             tty_print_char (c);
 415         }
 416     }
 417 }
 418 
 419 /* --------------------------------------------------------------------------------------------- */
 420 
 421 static void
 422 handle_console_freebsd (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 423 {
 424     switch (action)
 425     {
 426     case CONSOLE_INIT:
 427         console_init ();
 428         break;
 429 
 430     case CONSOLE_DONE:
 431         console_shutdown ();
 432         break;
 433 
 434     case CONSOLE_SAVE:
 435         console_save ();
 436         break;
 437 
 438     case CONSOLE_RESTORE:
 439         console_restore ();
 440         break;
 441     default:
 442         break;
 443     }
 444 }
 445 #endif /* __FreeBSD__ */
 446 
 447 /* --------------------------------------------------------------------------------------------- */
 448 /*** public functions ****************************************************************************/
 449 /* --------------------------------------------------------------------------------------------- */
 450 
 451 void
 452 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 453 {
 454     tty_set_normal_attrs ();
 455 
 456     if (look_for_rxvt_extensions ())
 457     {
 458         show_rxvt_contents (starty, begin_line, end_line);
 459         return;
 460     }
 461 #ifdef __linux__
 462     show_console_contents_linux (starty, begin_line, end_line);
 463 #elif defined (__FreeBSD__)
 464     show_console_contents_freebsd (starty, begin_line, end_line);
 465 #else
 466     mc_global.tty.console_flag = '\0';
 467 #endif
 468 }
 469 
 470 /* --------------------------------------------------------------------------------------------- */
 471 
 472 void
 473 handle_console (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 474 {
 475     (void) action;
 476 
 477     if (look_for_rxvt_extensions ())
 478         return;
 479 
 480 #ifdef __linux__
 481     handle_console_linux (action);
 482 #elif defined (__FreeBSD__)
 483     handle_console_freebsd (action);
 484 #endif
 485 }
 486 
 487 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */