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-2022
   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         {
 245             /* Convert enum (i.e. int) to char to write the correct value
 246              * (the least byte) regardless of machine endianness. */
 247             char act = (char) action;
 248 
 249             status = write (pipefd1[1], &act, 1);
 250         }
 251         if (action != CONSOLE_DONE)
 252         {
 253             /* Wait the console handler to do its job */
 254             status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
 255         }
 256         if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
 257         {
 258             /* We are done -> Let's clean up */
 259             pid_t ret;
 260             close (pipefd1[1]);
 261             close (pipefd2[0]);
 262             ret = waitpid (cons_saver_pid, &status, 0);
 263             (void) ret;
 264             mc_global.tty.console_flag = '\0';
 265         }
 266         break;
 267     default:
 268         break;
 269     }
 270 }
 271 
 272 #elif defined(__FreeBSD__)
 273 
 274 /* --------------------------------------------------------------------------------------------- */
 275 /**
 276  * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
 277  * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
 278  */
 279 
 280 static void
 281 console_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 282 {
 283     if (mc_global.tty.console_flag != '\0')
 284         return;
 285 
 286     screen_info.size = sizeof (screen_info);
 287     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 288         return;
 289 
 290     memset (&screen_shot, 0, sizeof (screen_shot));
 291     screen_shot.xsize = screen_info.mv_csz;
 292     screen_shot.ysize = screen_info.mv_rsz;
 293     screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
 294     if (screen_shot.buf != NULL)
 295         mc_global.tty.console_flag = '\001';
 296 }
 297 
 298 /* --------------------------------------------------------------------------------------------- */
 299 
 300 static void
 301 set_attr (unsigned attr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 302 {
 303     /*
 304      * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
 305      * to indices for ANSI sequences (red=1, green=2, blue=4).
 306      */
 307     static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 308     int bc, tc;
 309 
 310     tc = attr & 0xF;
 311     bc = (attr >> 4) & 0xF;
 312 
 313     printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
 314             color_map[tc & 7], color_map[bc & 7]);
 315 }
 316 
 317 /* --------------------------------------------------------------------------------------------- */
 318 
 319 static void
 320 console_restore (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 321 {
 322     int i, last;
 323 
 324     if (mc_global.tty.console_flag == '\0')
 325         return;
 326 
 327     cursor_to (0, 0);
 328 
 329     /* restoring all content up to cursor position */
 330     last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
 331     for (i = 0; i < last; ++i)
 332     {
 333         set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
 334         putc (screen_shot.buf[i] & 0xFF, stdout);
 335     }
 336 
 337     /* restoring cursor color */
 338     set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
 339 
 340     fflush (stdout);
 341 }
 342 
 343 /* --------------------------------------------------------------------------------------------- */
 344 
 345 static void
 346 console_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 347 {
 348     if (mc_global.tty.console_flag == '\0')
 349         return;
 350 
 351     g_free (screen_shot.buf);
 352 
 353     mc_global.tty.console_flag = '\0';
 354 }
 355 
 356 /* --------------------------------------------------------------------------------------------- */
 357 
 358 static void
 359 console_save (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 360 {
 361     int i;
 362     scrmap_t map;
 363     scrmap_t revmap;
 364 
 365     if (mc_global.tty.console_flag == '\0')
 366         return;
 367 
 368     /* screen_info.size is already set in console_init() */
 369     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 370     {
 371         console_shutdown ();
 372         return;
 373     }
 374 
 375     /* handle console resize */
 376     if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
 377     {
 378         console_shutdown ();
 379         console_init ();
 380     }
 381 
 382     if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
 383     {
 384         console_shutdown ();
 385         return;
 386     }
 387 
 388     if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
 389     {
 390         console_shutdown ();
 391         return;
 392     }
 393 
 394     for (i = 0; i < 256; i++)
 395     {
 396         char *p = memchr (map.scrmap, i, 256);
 397         revmap.scrmap[i] = p ? p - map.scrmap : i;
 398     }
 399 
 400     for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
 401     {
 402         /* *INDENT-OFF* */
 403         screen_shot.buf[i] = (screen_shot.buf[i] & 0xff00) 
 404             | (unsigned char) revmap.scrmap[screen_shot.buf[i] & 0xff];
 405         /* *INDENT-ON* */
 406     }
 407 }
 408 
 409 /* --------------------------------------------------------------------------------------------- */
 410 
 411 static void
 412 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 413 {
 414     int col, line;
 415     char c;
 416 
 417     if (mc_global.tty.console_flag == '\0')
 418         return;
 419 
 420     for (line = begin_line; line <= end_line; line++)
 421     {
 422         tty_gotoyx (starty + line - begin_line, 0);
 423         for (col = 0; col < MIN (COLS, screen_info.mv_csz); col++)
 424         {
 425             c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
 426             tty_print_char (c);
 427         }
 428     }
 429 }
 430 
 431 /* --------------------------------------------------------------------------------------------- */
 432 
 433 static void
 434 handle_console_freebsd (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 435 {
 436     switch (action)
 437     {
 438     case CONSOLE_INIT:
 439         console_init ();
 440         break;
 441 
 442     case CONSOLE_DONE:
 443         console_shutdown ();
 444         break;
 445 
 446     case CONSOLE_SAVE:
 447         console_save ();
 448         break;
 449 
 450     case CONSOLE_RESTORE:
 451         console_restore ();
 452         break;
 453     default:
 454         break;
 455     }
 456 }
 457 #endif /* __FreeBSD__ */
 458 
 459 /* --------------------------------------------------------------------------------------------- */
 460 /*** public functions ****************************************************************************/
 461 /* --------------------------------------------------------------------------------------------- */
 462 
 463 void
 464 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 465 {
 466     tty_set_normal_attrs ();
 467 
 468     if (look_for_rxvt_extensions ())
 469     {
 470         show_rxvt_contents (starty, begin_line, end_line);
 471         return;
 472     }
 473 #ifdef __linux__
 474     show_console_contents_linux (starty, begin_line, end_line);
 475 #elif defined (__FreeBSD__)
 476     show_console_contents_freebsd (starty, begin_line, end_line);
 477 #else
 478     mc_global.tty.console_flag = '\0';
 479 #endif
 480 }
 481 
 482 /* --------------------------------------------------------------------------------------------- */
 483 
 484 void
 485 handle_console (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 486 {
 487     (void) action;
 488 
 489     if (look_for_rxvt_extensions ())
 490         return;
 491 
 492 #ifdef __linux__
 493     handle_console_linux (action);
 494 #elif defined (__FreeBSD__)
 495     handle_console_freebsd (action);
 496 #endif
 497 }
 498 
 499 /* --------------------------------------------------------------------------------------------- */

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