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-2024
   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 /*** forward declarations (file scope functions) *************************************************/
  72 
  73 /*** file scope variables ************************************************************************/
  74 
  75 #ifdef __linux__
  76 /* The cons saver can't have a pid of 1, used to prevent bunches of
  77  * #ifdef linux */
  78 static int pipefd1[2] = { -1, -1 };
  79 static int pipefd2[2] = { -1, -1 };
  80 #elif defined(__FreeBSD__)
  81 static struct scrshot screen_shot;
  82 static struct vid_info screen_info;
  83 #endif /* __linux__ */
  84 
  85 /* --------------------------------------------------------------------------------------------- */
  86 /*** file scope functions ************************************************************************/
  87 /* --------------------------------------------------------------------------------------------- */
  88 
  89 #ifdef __linux__
  90 static void
  91 show_console_contents_linux (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
  92 {
  93     unsigned char message = 0;
  94     unsigned short bytes = 0;
  95     int i;
  96     ssize_t ret;
  97 
  98     /* Is tty console? */
  99     if (mc_global.tty.console_flag == '\0')
 100         return;
 101     /* Paranoid: Is the cons.saver still running? */
 102     if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
 103     {
 104         cons_saver_pid = 0;
 105         mc_global.tty.console_flag = '\0';
 106         return;
 107     }
 108 
 109     /* Send command to the console handler */
 110     message = CONSOLE_CONTENTS;
 111     ret = write (pipefd1[1], &message, 1);
 112     /* Check for outdated cons.saver */
 113     ret = read (pipefd2[0], &message, 1);
 114     if (message != CONSOLE_CONTENTS)
 115         return;
 116 
 117     /* Send the range of lines that we want */
 118     ret = write (pipefd1[1], &begin_line, 1);
 119     ret = write (pipefd1[1], &end_line, 1);
 120     /* Read the corresponding number of bytes */
 121     ret = read (pipefd2[0], &bytes, 2);
 122 
 123     /* Read the bytes and output them */
 124     for (i = 0; i < bytes; i++)
 125     {
 126         if ((i % COLS) == 0)
 127             tty_gotoyx (starty + (i / COLS), 0);
 128         ret = read (pipefd2[0], &message, 1);
 129         tty_print_char (message);
 130     }
 131 
 132     /* Read the value of the mc_global.tty.console_flag */
 133     ret = read (pipefd2[0], &message, 1);
 134     (void) ret;
 135 }
 136 
 137 /* --------------------------------------------------------------------------------------------- */
 138 
 139 static void
 140 handle_console_linux (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 141 {
 142     int status;
 143 
 144     switch (action)
 145     {
 146     case CONSOLE_INIT:
 147         /* Close old pipe ends in case it is the 2nd time we run cons.saver */
 148         status = close (pipefd1[1]);
 149         status = close (pipefd2[0]);
 150         /* Create two pipes for communication */
 151         if (!((pipe (pipefd1) == 0) && ((pipe (pipefd2)) == 0)))
 152         {
 153             mc_global.tty.console_flag = '\0';
 154             break;
 155         }
 156         /* Get the console saver running */
 157         cons_saver_pid = fork ();
 158         if (cons_saver_pid < 0)
 159         {
 160             /* Cannot fork */
 161             /* Delete pipes */
 162             status = close (pipefd1[1]);
 163             status = close (pipefd1[0]);
 164             status = close (pipefd2[1]);
 165             status = close (pipefd2[0]);
 166             mc_global.tty.console_flag = '\0';
 167         }
 168         else if (cons_saver_pid > 0)
 169         {
 170             /* Parent */
 171             /* Close the extra pipe ends */
 172             status = close (pipefd1[0]);
 173             status = close (pipefd2[1]);
 174             /* Was the child successful? */
 175             status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
 176             if (mc_global.tty.console_flag == '\0')
 177             {
 178                 pid_t ret;
 179                 status = close (pipefd1[1]);
 180                 status = close (pipefd2[0]);
 181                 ret = waitpid (cons_saver_pid, &status, 0);
 182                 (void) ret;
 183             }
 184         }
 185         else
 186         {
 187             /* Child */
 188             char *tty_name;
 189 
 190             /* Close the extra pipe ends */
 191             status = close (pipefd1[1]);
 192             status = close (pipefd2[0]);
 193             tty_name = ttyname (0);
 194             /* Bind the pipe 0 to the standard input */
 195             do
 196             {
 197                 gboolean ok;
 198 
 199                 if (dup2 (pipefd1[0], STDIN_FILENO) == -1)
 200                     break;
 201                 status = close (pipefd1[0]);
 202                 /* Bind the pipe 1 to the standard output */
 203                 if (dup2 (pipefd2[1], STDOUT_FILENO) == -1)
 204                     break;
 205 
 206                 status = close (pipefd2[1]);
 207                 /* Bind standard error to /dev/null */
 208                 status = open ("/dev/null", O_WRONLY);
 209                 if (status == -1)
 210                     break;
 211                 ok = dup2 (status, STDERR_FILENO) != -1;
 212                 status = close (status);
 213                 if (!ok)
 214                     break;
 215 
 216                 if (tty_name != NULL)
 217                 {
 218                     char *mc_conssaver;
 219 
 220                     /* Exec the console save/restore handler */
 221                     mc_conssaver = mc_build_filename (SAVERDIR, "cons.saver", (char *) NULL);
 222                     execl (mc_conssaver, "cons.saver", tty_name, (char *) NULL);
 223                 }
 224                 /* Console is not a tty or execl() failed */
 225             }
 226             while (0);
 227             mc_global.tty.console_flag = '\0';
 228             status = write (1, &mc_global.tty.console_flag, 1);
 229             my_exit (3);
 230         }                       /* if (cons_saver_pid ...) */
 231         break;
 232 
 233     case CONSOLE_DONE:
 234     case CONSOLE_SAVE:
 235     case CONSOLE_RESTORE:
 236         /* Is tty console? */
 237         if (mc_global.tty.console_flag == '\0')
 238             return;
 239         /* Paranoid: Is the cons.saver still running? */
 240         if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT))
 241         {
 242             cons_saver_pid = 0;
 243             mc_global.tty.console_flag = '\0';
 244             return;
 245         }
 246         /* Send command to the console handler */
 247         {
 248             /* Convert enum (i.e. int) to char to write the correct value
 249              * (the least byte) regardless of machine endianness. */
 250             char act = (char) action;
 251 
 252             status = write (pipefd1[1], &act, 1);
 253         }
 254         if (action != CONSOLE_DONE)
 255         {
 256             /* Wait the console handler to do its job */
 257             status = read (pipefd2[0], &mc_global.tty.console_flag, 1);
 258         }
 259         if (action == CONSOLE_DONE || mc_global.tty.console_flag == '\0')
 260         {
 261             /* We are done -> Let's clean up */
 262             pid_t ret;
 263             close (pipefd1[1]);
 264             close (pipefd2[0]);
 265             ret = waitpid (cons_saver_pid, &status, 0);
 266             (void) ret;
 267             mc_global.tty.console_flag = '\0';
 268         }
 269         break;
 270     default:
 271         break;
 272     }
 273 }
 274 
 275 #elif defined(__FreeBSD__)
 276 
 277 /* --------------------------------------------------------------------------------------------- */
 278 /**
 279  * FreeBSD support copyright (C) 2003 Alexander Serkov <serkov@ukrpost.net>.
 280  * Support for screenmaps by Max Khon <fjoe@FreeBSD.org>
 281  */
 282 
 283 static void
 284 console_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 285 {
 286     if (mc_global.tty.console_flag != '\0')
 287         return;
 288 
 289     screen_info.size = sizeof (screen_info);
 290     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 291         return;
 292 
 293     memset (&screen_shot, 0, sizeof (screen_shot));
 294     screen_shot.xsize = screen_info.mv_csz;
 295     screen_shot.ysize = screen_info.mv_rsz;
 296     screen_shot.buf = g_try_malloc (screen_info.mv_csz * screen_info.mv_rsz * 2);
 297     if (screen_shot.buf != NULL)
 298         mc_global.tty.console_flag = '\001';
 299 }
 300 
 301 /* --------------------------------------------------------------------------------------------- */
 302 
 303 static void
 304 set_attr (unsigned attr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 305 {
 306     /*
 307      * Convert color indices returned by SCRSHOT (red=4, green=2, blue=1)
 308      * to indices for ANSI sequences (red=1, green=2, blue=4).
 309      */
 310     static const int color_map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 311     int bc, tc;
 312 
 313     tc = attr & 0xF;
 314     bc = (attr >> 4) & 0xF;
 315 
 316     printf ("\x1B[%d;%d;3%d;4%dm", (bc & 8) ? 5 : 25, (tc & 8) ? 1 : 22,
 317             color_map[tc & 7], color_map[bc & 7]);
 318 }
 319 
 320 /* --------------------------------------------------------------------------------------------- */
 321 
 322 static void
 323 console_restore (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 324 {
 325     int i, last;
 326 
 327     if (mc_global.tty.console_flag == '\0')
 328         return;
 329 
 330     cursor_to (0, 0);
 331 
 332     /* restoring all content up to cursor position */
 333     last = screen_info.mv_row * screen_info.mv_csz + screen_info.mv_col;
 334     for (i = 0; i < last; ++i)
 335     {
 336         set_attr ((screen_shot.buf[i] >> 8) & 0xFF);
 337         putc (screen_shot.buf[i] & 0xFF, stdout);
 338     }
 339 
 340     /* restoring cursor color */
 341     set_attr ((screen_shot.buf[last] >> 8) & 0xFF);
 342 
 343     fflush (stdout);
 344 }
 345 
 346 /* --------------------------------------------------------------------------------------------- */
 347 
 348 static void
 349 console_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 350 {
 351     if (mc_global.tty.console_flag == '\0')
 352         return;
 353 
 354     g_free (screen_shot.buf);
 355 
 356     mc_global.tty.console_flag = '\0';
 357 }
 358 
 359 /* --------------------------------------------------------------------------------------------- */
 360 
 361 static void
 362 console_save (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 363 {
 364     int i;
 365     scrmap_t map;
 366     scrmap_t revmap;
 367 
 368     if (mc_global.tty.console_flag == '\0')
 369         return;
 370 
 371     /* screen_info.size is already set in console_init() */
 372     if (ioctl (FD_OUT, CONS_GETINFO, &screen_info) == -1)
 373     {
 374         console_shutdown ();
 375         return;
 376     }
 377 
 378     /* handle console resize */
 379     if (screen_info.mv_csz != screen_shot.xsize || screen_info.mv_rsz != screen_shot.ysize)
 380     {
 381         console_shutdown ();
 382         console_init ();
 383     }
 384 
 385     if (ioctl (FD_OUT, CONS_SCRSHOT, &screen_shot) == -1)
 386     {
 387         console_shutdown ();
 388         return;
 389     }
 390 
 391     if (ioctl (FD_OUT, GIO_SCRNMAP, &map) == -1)
 392     {
 393         console_shutdown ();
 394         return;
 395     }
 396 
 397     for (i = 0; i < 256; i++)
 398     {
 399         char *p = memchr (map.scrmap, i, 256);
 400         revmap.scrmap[i] = p ? p - map.scrmap : i;
 401     }
 402 
 403     for (i = 0; i < screen_shot.xsize * screen_shot.ysize; i++)
 404     {
 405         /* *INDENT-OFF* */
 406         screen_shot.buf[i] = (screen_shot.buf[i] & 0xff00) 
 407             | (unsigned char) revmap.scrmap[screen_shot.buf[i] & 0xff];
 408         /* *INDENT-ON* */
 409     }
 410 }
 411 
 412 /* --------------------------------------------------------------------------------------------- */
 413 
 414 static void
 415 show_console_contents_freebsd (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 416 {
 417     int col, line;
 418     char c;
 419 
 420     if (mc_global.tty.console_flag == '\0')
 421         return;
 422 
 423     for (line = begin_line; line <= end_line; line++)
 424     {
 425         tty_gotoyx (starty + line - begin_line, 0);
 426         for (col = 0; col < MIN (COLS, screen_info.mv_csz); col++)
 427         {
 428             c = screen_shot.buf[line * screen_info.mv_csz + col] & 0xFF;
 429             tty_print_char (c);
 430         }
 431     }
 432 }
 433 
 434 /* --------------------------------------------------------------------------------------------- */
 435 
 436 static void
 437 handle_console_freebsd (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 438 {
 439     switch (action)
 440     {
 441     case CONSOLE_INIT:
 442         console_init ();
 443         break;
 444 
 445     case CONSOLE_DONE:
 446         console_shutdown ();
 447         break;
 448 
 449     case CONSOLE_SAVE:
 450         console_save ();
 451         break;
 452 
 453     case CONSOLE_RESTORE:
 454         console_restore ();
 455         break;
 456     default:
 457         break;
 458     }
 459 }
 460 #endif /* __FreeBSD__ */
 461 
 462 /* --------------------------------------------------------------------------------------------- */
 463 /*** public functions ****************************************************************************/
 464 /* --------------------------------------------------------------------------------------------- */
 465 
 466 void
 467 show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 468 {
 469     tty_set_normal_attrs ();
 470 
 471     if (look_for_rxvt_extensions ())
 472     {
 473         show_rxvt_contents (starty, begin_line, end_line);
 474         return;
 475     }
 476 #ifdef __linux__
 477     show_console_contents_linux (starty, begin_line, end_line);
 478 #elif defined (__FreeBSD__)
 479     show_console_contents_freebsd (starty, begin_line, end_line);
 480 #else
 481     mc_global.tty.console_flag = '\0';
 482 #endif
 483 }
 484 
 485 /* --------------------------------------------------------------------------------------------- */
 486 
 487 void
 488 handle_console (console_action_t action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 489 {
 490     (void) action;
 491 
 492     if (look_for_rxvt_extensions ())
 493         return;
 494 
 495 #ifdef __linux__
 496     handle_console_linux (action);
 497 #elif defined (__FreeBSD__)
 498     handle_console_freebsd (action);
 499 #endif
 500 }
 501 
 502 /* --------------------------------------------------------------------------------------------- */

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