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-2021
   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                 gboolean ok;
 195 
 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;
 202 
 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;
 212 
 213                 if (tty_name != NULL)
 214                 {
 215                     char *mc_conssaver;
 216 
 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);
 220                 }
 221                 /* Console is not a tty or execl() failed */
 222             }
 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;
 229 
 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))
 238         {
 239             cons_saver_pid = 0;
 240             mc_global.tty.console_flag = '\0';
 241             return;
 242         }
 243         /* Send command to the console handler */
 244         status = write (pipefd1[1], &action, 1);
 245         if (action != CONSOLE_DONE)
 246         {
 247             /* Wait the console handler to do its job */
 248             status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
 249         }
 250         if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
 251         {
 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';
 259         }
 260         break;
 261     default:
 262         break;
 263     }
 264 }
 265 
 266 #elif defined(__FreeBSD__)
 267 
 268 /* --------------------------------------------------------------------------------------------- */
 269 /**
 270  * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
 271  * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
 272  */
 273 
 274 static void
 275 console_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 276 {
 277     if (mc_global.tty.console_flag != '\0')
 278         return;
 279 
 280     screen_info.size = sizeof (screen_info);
 281     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 282         return;
 283 
 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';
 290 }
 291 
 292 /* --------------------------------------------------------------------------------------------- */
 293 
 294 static void
 295 set_attr (unsigned attr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 296 {
 297     /*
 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).
 300      */
 301     static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 302     int bc, tc;
 303 
 304     tc = attr & 0xF;
 305     bc = (attr >> 4) & 0xF;
 306 
 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]);
 309 }
 310 
 311 /* --------------------------------------------------------------------------------------------- */
 312 
 313 static void
 314 console_restore (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 315 {
 316     int i, last;
 317 
 318     if (mc_global.tty.console_flag == '\0')
 319         return;
 320 
 321     cursor_to (0, 0);
 322 
 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)
 326     {
 327         set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
 328         putc (screen_shot.buf[i] & 0xFF, stdout);
 329     }
 330 
 331     /* restoring cursor color */
 332     set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
 333 
 334     fflush (stdout);
 335 }
 336 
 337 /* --------------------------------------------------------------------------------------------- */
 338 
 339 static void
 340 console_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 341 {
 342     if (mc_global.tty.console_flag == '\0')
 343         return;
 344 
 345     g_free (screen_shot.buf);
 346 
 347     mc_global.tty.console_flag = '\0';
 348 }
 349 
 350 /* --------------------------------------------------------------------------------------------- */
 351 
 352 static void
 353 console_save (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 354 {
 355     int i;
 356     scrmap_t map;
 357     scrmap_t revmap;
 358 
 359     if (mc_global.tty.console_flag == '\0')
 360         return;
 361 
 362     /* screen_info.size is already set in console_init() */
 363     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 364     {
 365         console_shutdown ();
 366         return;
 367     }
 368 
 369     /* handle console resize */
 370     if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
 371     {
 372         console_shutdown ();
 373         console_init ();
 374     }
 375 
 376     if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
 377     {
 378         console_shutdown ();
 379         return;
 380     }
 381 
 382     if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
 383     {
 384         console_shutdown ();
 385         return;
 386     }
 387 
 388     for (i = 0; i < 256; i++)
 389     {
 390         char *p = memchr (map.scrmap, i, 256);
 391         revmap.scrmap[i] = p ? p - map.scrmap : i;
 392     }
 393 
 394     for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
 395     {
 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* */
 400     }
 401 }
 402 
 403 /* --------------------------------------------------------------------------------------------- */
 404 
 405 static void
 406 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 407 {
 408     int col, line;
 409     char c;
 410 
 411     if (mc_global.tty.console_flag == '\0')
 412         return;
 413 
 414     for (line = begin_line; line <= end_line; line++)
 415     {
 416         tty_gotoyx (starty + line - begin_line, 0);
 417         for (col = 0; col < MIN (COLS, screen_info.mv_csz); col++)
 418         {
 419             c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
 420             tty_print_char (c);
 421         }
 422     }
 423 }
 424 
 425 /* --------------------------------------------------------------------------------------------- */
 426 
 427 static void
 428 handle_console_freebsd (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 429 {
 430     switch (action)
 431     {
 432     case CONSOLE_INIT:
 433         console_init ();
 434         break;
 435 
 436     case CONSOLE_DONE:
 437         console_shutdown ();
 438         break;
 439 
 440     case CONSOLE_SAVE:
 441         console_save ();
 442         break;
 443 
 444     case CONSOLE_RESTORE:
 445         console_restore ();
 446         break;
 447     default:
 448         break;
 449     }
 450 }
 451 #endif /* __FreeBSD__ */
 452 
 453 /* --------------------------------------------------------------------------------------------- */
 454 /*** public functions ****************************************************************************/
 455 /* --------------------------------------------------------------------------------------------- */
 456 
 457 void
 458 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 459 {
 460     tty_set_normal_attrs ();
 461 
 462     if (look_for_rxvt_extensions ())
 463     {
 464         show_rxvt_contents (starty, begin_line, end_line);
 465         return;
 466     }
 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
 474 }
 475 
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 void
 479 handle_console (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 480 {
 481     (void) action;
 482 
 483     if (look_for_rxvt_extensions ())
 484         return;
 485 
 486 #ifdef __linux__
 487     handle_console_linux (action);
 488 #elif defined (__FreeBSD__)
 489     handle_console_freebsd (action);
 490 #endif
 491 }
 492 
 493 /* --------------------------------------------------------------------------------------------- */

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