root/src/main.c

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

DEFINITIONS

This source file includes following definitions.
  1. check_codeset
  2. OS_Setup
  3. sigchld_handler_no_subshell
  4. init_sigchld
  5. main

   1 /*
   2    Main program for the Midnight Commander
   3 
   4    Copyright (C) 1994-2018
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Miguel de Icaza, 1994, 1995, 1996, 1997
   9    Janne Kukonlehto, 1994, 1995
  10    Norbert Warmuth, 1997
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file main.c
  29  *  \brief Source: this is a main module
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <ctype.h>
  35 #include <errno.h>
  36 #include <locale.h>
  37 #include <pwd.h>                /* for username in xterm title */
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 #include <sys/wait.h>
  42 #include <signal.h>
  43 
  44 #include "lib/global.h"
  45 
  46 #include "lib/event.h"
  47 #include "lib/tty/tty.h"
  48 #include "lib/tty/key.h"        /* For init_key() */
  49 #include "lib/tty/mouse.h"      /* init_mouse() */
  50 #include "lib/timer.h"
  51 #include "lib/skin.h"
  52 #include "lib/filehighlight.h"
  53 #include "lib/fileloc.h"
  54 #include "lib/strutil.h"
  55 #include "lib/util.h"
  56 #include "lib/vfs/vfs.h"        /* vfs_init(), vfs_shut() */
  57 
  58 #include "filemanager/midnight.h"       /* current_panel */
  59 #include "filemanager/treestore.h"      /* tree_store_save */
  60 #include "filemanager/layout.h" /* command_prompt */
  61 #include "filemanager/ext.h"    /* flush_extension_file() */
  62 #include "filemanager/command.h"        /* cmdline */
  63 #include "filemanager/panel.h"  /* panalized_panel */
  64 
  65 #include "vfs/plugins_init.h"
  66 
  67 #include "events_init.h"
  68 #include "args.h"
  69 #ifdef ENABLE_SUBSHELL
  70 #include "subshell/subshell.h"
  71 #endif
  72 #include "setup.h"              /* load_setup() */
  73 
  74 #ifdef HAVE_CHARSET
  75 #include "lib/charsets.h"
  76 #include "selcodepage.h"
  77 #endif /* HAVE_CHARSET */
  78 
  79 #include "consaver/cons.saver.h"        /* cons_saver_pid */
  80 
  81 /*** global variables ****************************************************************************/
  82 
  83 /*** file scope macro definitions ****************************************************************/
  84 
  85 /*** file scope type declarations ****************************************************************/
  86 
  87 /*** file scope variables ************************************************************************/
  88 
  89 /*** file scope functions ************************************************************************/
  90 /* --------------------------------------------------------------------------------------------- */
  91 
  92 static void
  93 check_codeset (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  94 {
  95     const char *current_system_codepage = NULL;
  96 
  97     current_system_codepage = str_detect_termencoding ();
  98 
  99 #ifdef HAVE_CHARSET
 100     {
 101         const char *_display_codepage;
 102 
 103         _display_codepage = get_codepage_id (mc_global.display_codepage);
 104 
 105         if (strcmp (_display_codepage, current_system_codepage) != 0)
 106         {
 107             mc_global.display_codepage = get_codepage_index (current_system_codepage);
 108             if (mc_global.display_codepage == -1)
 109                 mc_global.display_codepage = 0;
 110 
 111             mc_config_set_string (mc_global.main_config, CONFIG_MISC_SECTION, "display_codepage",
 112                                   cp_display);
 113         }
 114     }
 115 #endif
 116 
 117     mc_global.utf8_display = str_isutf8 (current_system_codepage);
 118 }
 119 
 120 /* --------------------------------------------------------------------------------------------- */
 121 /** POSIX version.  The only version we support.  */
 122 
 123 static void
 124 OS_Setup (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 125 {
 126     const char *datadir_env;
 127 
 128     mc_shell_init ();
 129 
 130     /* This is the directory, where MC was installed, on Unix this is DATADIR */
 131     /* and can be overriden by the MC_DATADIR environment variable */
 132     datadir_env = g_getenv ("MC_DATADIR");
 133     if (datadir_env != NULL)
 134         mc_global.sysconfig_dir = g_strdup (datadir_env);
 135     else
 136         mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
 137 
 138     mc_global.share_data_dir = g_strdup (DATADIR);
 139 }
 140 
 141 /* --------------------------------------------------------------------------------------------- */
 142 
 143 static void
 144 sigchld_handler_no_subshell (int sig)
     /* [previous][next][first][last][top][bottom][index][help]  */
 145 {
 146 #ifdef __linux__
 147     int pid, status;
 148 
 149     if (mc_global.tty.console_flag == '\0')
 150         return;
 151 
 152     /* COMMENT: if it were true that after the call to handle_console(..INIT)
 153        the value of mc_global.tty.console_flag never changed, we could simply not install
 154        this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
 155 
 156     /* That comment is no longer true.  We need to wait() on a sigchld
 157        handler (that's at least what the tarfs code expects currently). */
 158 
 159     pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
 160 
 161     if (pid == cons_saver_pid)
 162     {
 163         if (WIFSTOPPED (status))
 164         {
 165             /* Someone has stopped cons.saver - restart it */
 166             kill (pid, SIGCONT);
 167         }
 168         else
 169         {
 170             /* cons.saver has died - disable console saving */
 171             handle_console (CONSOLE_DONE);
 172             mc_global.tty.console_flag = '\0';
 173         }
 174     }
 175     /* If we got here, some other child exited; ignore it */
 176 #endif /* __linux__ */
 177 
 178     (void) sig;
 179 }
 180 
 181 /* --------------------------------------------------------------------------------------------- */
 182 
 183 static void
 184 init_sigchld (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 185 {
 186     struct sigaction sigchld_action;
 187 
 188     memset (&sigchld_action, 0, sizeof (sigchld_action));
 189     sigchld_action.sa_handler =
 190 #ifdef ENABLE_SUBSHELL
 191         mc_global.tty.use_subshell ? sigchld_handler :
 192 #endif /* ENABLE_SUBSHELL */
 193         sigchld_handler_no_subshell;
 194 
 195     sigemptyset (&sigchld_action.sa_mask);
 196 
 197 #ifdef SA_RESTART
 198     sigchld_action.sa_flags = SA_RESTART;
 199 #endif /* !SA_RESTART */
 200 
 201     if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
 202     {
 203 #ifdef ENABLE_SUBSHELL
 204         /*
 205          * This may happen on QNX Neutrino 6, where SA_RESTART
 206          * is defined but not implemented.  Fallback to no subshell.
 207          */
 208         mc_global.tty.use_subshell = FALSE;
 209 #endif /* ENABLE_SUBSHELL */
 210     }
 211 }
 212 
 213 /* --------------------------------------------------------------------------------------------- */
 214 /*** public functions ****************************************************************************/
 215 /* --------------------------------------------------------------------------------------------- */
 216 
 217 int
 218 main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help]  */
 219 {
 220     GError *mcerror = NULL;
 221     gboolean config_migrated = FALSE;
 222     char *config_migrate_msg = NULL;
 223     int exit_code = EXIT_FAILURE;
 224 
 225     mc_global.timer = mc_timer_new ();
 226 
 227     /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
 228 #ifdef HAVE_SETLOCALE
 229     (void) setlocale (LC_ALL, "");
 230 #endif
 231     (void) bindtextdomain (PACKAGE, LOCALEDIR);
 232     (void) textdomain (PACKAGE);
 233 
 234     /* do this before args parsing */
 235     str_init_strings (NULL);
 236 
 237     mc_setup_run_mode (argv);   /* are we mc? editor? viewer? etc... */
 238 
 239     if (!mc_args_parse (&argc, &argv, "mc", &mcerror))
 240     {
 241       startup_exit_falure:
 242         fprintf (stderr, _("Failed to run:\n%s\n"), mcerror->message);
 243         g_error_free (mcerror);
 244       startup_exit_ok:
 245         mc_shell_deinit ();
 246         str_uninit_strings ();
 247         mc_timer_destroy (mc_global.timer);
 248         return exit_code;
 249     }
 250 
 251     /* do this before mc_args_show_info () to view paths in the --datadir-info output */
 252     OS_Setup ();
 253 
 254     if (!g_path_is_absolute (mc_config_get_home_dir ()))
 255     {
 256         mc_propagate_error (&mcerror, 0, "%s: %s", _("Home directory path is not absolute"),
 257                             mc_config_get_home_dir ());
 258         mc_event_deinit (NULL);
 259         goto startup_exit_falure;
 260     }
 261 
 262     if (!mc_args_show_info ())
 263     {
 264         exit_code = EXIT_SUCCESS;
 265         goto startup_exit_ok;
 266     }
 267 
 268     if (!events_init (&mcerror))
 269         goto startup_exit_falure;
 270 
 271     mc_config_init_config_paths (&mcerror);
 272     config_migrated = mc_config_migrate_from_old_place (&mcerror, &config_migrate_msg);
 273     if (mcerror != NULL)
 274     {
 275         mc_event_deinit (NULL);
 276         goto startup_exit_falure;
 277     }
 278 
 279     vfs_init ();
 280     vfs_plugins_init ();
 281 
 282     load_setup ();
 283 
 284     /* Must be done after load_setup because depends on mc_global.vfs.cd_symlinks */
 285     vfs_setup_work_dir ();
 286 
 287     /* Set up temporary directory after VFS initialization */
 288     mc_tmpdir ();
 289 
 290     /* do this after vfs initialization and vfs working directory setup
 291        due to mc_setctl() and mcedit_arg_vpath_new() calls in mc_setup_by_args() */
 292     if (!mc_setup_by_args (argc, argv, &mcerror))
 293     {
 294         vfs_shut ();
 295         done_setup ();
 296         g_free (saved_other_dir);
 297         mc_event_deinit (NULL);
 298         goto startup_exit_falure;
 299     }
 300 
 301     /* Resolve the other_dir panel option.
 302      * 1. Must be done after vfs_setup_work_dir().
 303      * 2. Must be done after mc_setup_by_args() because of mc_run_mode.
 304      */
 305     if (mc_global.mc_run_mode == MC_RUN_FULL)
 306     {
 307         char *buffer;
 308         vfs_path_t *vpath;
 309 
 310         buffer = mc_config_get_string (mc_global.panels_config, "Dirs", "other_dir", ".");
 311         vpath = vfs_path_from_str (buffer);
 312         if (vfs_file_is_local (vpath))
 313             saved_other_dir = buffer;
 314         else
 315             g_free (buffer);
 316         vfs_path_free (vpath);
 317     }
 318 
 319     /* check terminal type
 320      * $TERM must be set and not empty
 321      * mc_global.tty.xterm_flag is used in init_key() and tty_init()
 322      * Do this after mc_args_handle() where mc_args__force_xterm is set up.
 323      */
 324     mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
 325 
 326     /* NOTE: This has to be called before tty_init or whatever routine
 327        calls any define_sequence */
 328     init_key ();
 329 
 330     /* Must be done before installing the SIGCHLD handler [[FIXME]] */
 331     handle_console (CONSOLE_INIT);
 332 
 333 #ifdef ENABLE_SUBSHELL
 334     /* Don't use subshell when invoked as viewer or editor */
 335     if (mc_global.mc_run_mode != MC_RUN_FULL)
 336         mc_global.tty.use_subshell = FALSE;
 337 
 338     if (mc_global.tty.use_subshell)
 339         subshell_get_console_attributes ();
 340 #endif /* ENABLE_SUBSHELL */
 341 
 342     /* Install the SIGCHLD handler; must be done before init_subshell() */
 343     init_sigchld ();
 344 
 345     /* We need this, since ncurses endwin () doesn't restore the signals */
 346     save_stop_handler ();
 347 
 348     /* Must be done before init_subshell, to set up the terminal size: */
 349     /* FIXME: Should be removed and LINES and COLS computed on subshell */
 350     tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
 351 
 352     /* start check mc_global.display_codepage and mc_global.source_codepage */
 353     check_codeset ();
 354 
 355     /* Removing this from the X code let's us type C-c */
 356     load_key_defs ();
 357 
 358     load_keymap_defs (!mc_args__nokeymap);
 359 
 360 #ifdef USE_INTERNAL_EDIT
 361     macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
 362 #endif /* USE_INTERNAL_EDIT */
 363 
 364     tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
 365 
 366     mc_skin_init (NULL, &mcerror);
 367     dlg_set_default_colors ();
 368     input_set_default_colors ();
 369     if (mc_global.mc_run_mode == MC_RUN_FULL)
 370         command_set_default_colors ();
 371 
 372     mc_error_message (&mcerror, NULL);
 373 
 374 #ifdef ENABLE_SUBSHELL
 375     /* Done here to ensure that the subshell doesn't  */
 376     /* inherit the file descriptors opened below, etc */
 377     if (mc_global.tty.use_subshell)
 378         init_subshell ();
 379 #endif /* ENABLE_SUBSHELL */
 380 
 381     /* Also done after init_subshell, to save any shell init file messages */
 382     if (mc_global.tty.console_flag != '\0')
 383         handle_console (CONSOLE_SAVE);
 384 
 385     if (mc_global.tty.alternate_plus_minus)
 386         application_keypad_mode ();
 387 
 388     /* Done after subshell initialization to allow select and paste text by mouse
 389        w/o Shift button in subshell in the native console */
 390     init_mouse ();
 391 
 392     /* Done after tty_enter_ca_mode (tty_init) because in VTE bracketed mode is
 393        separate for the normal and alternate screens */
 394     enable_bracketed_paste ();
 395 
 396     /* subshell_prompt is NULL here */
 397     mc_prompt = (geteuid () == 0) ? "# " : "$ ";
 398 
 399     if (config_migrated)
 400     {
 401         message (D_ERROR, _("Warning"), "%s", config_migrate_msg);
 402         g_free (config_migrate_msg);
 403     }
 404 
 405     /* Program main loop */
 406     if (mc_global.midnight_shutdown)
 407         exit_code = EXIT_SUCCESS;
 408     else
 409         exit_code = do_nc ()? EXIT_SUCCESS : EXIT_FAILURE;
 410 
 411     disable_bracketed_paste ();
 412 
 413     disable_mouse ();
 414 
 415     /* Save the tree store */
 416     (void) tree_store_save ();
 417 
 418     free_keymap_defs ();
 419 
 420     /* Virtual File System shutdown */
 421     vfs_shut ();
 422 
 423     flush_extension_file ();    /* does only free memory */
 424 
 425     mc_skin_deinit ();
 426     tty_colors_done ();
 427 
 428     tty_shutdown ();
 429 
 430     done_setup ();
 431 
 432     if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
 433         handle_console (CONSOLE_RESTORE);
 434     if (mc_global.tty.alternate_plus_minus)
 435         numeric_keypad_mode ();
 436 
 437     (void) signal (SIGCHLD, SIG_DFL);   /* Disable the SIGCHLD handler */
 438 
 439     if (mc_global.tty.console_flag != '\0')
 440         handle_console (CONSOLE_DONE);
 441 
 442     if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
 443         && last_wd_string != NULL && !print_last_revert)
 444     {
 445         int last_wd_fd;
 446 
 447         last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
 448                            S_IRUSR | S_IWUSR);
 449         if (last_wd_fd != -1)
 450         {
 451             ssize_t ret1;
 452             int ret2;
 453             ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
 454             ret2 = close (last_wd_fd);
 455             (void) ret1;
 456             (void) ret2;
 457         }
 458     }
 459     g_free (last_wd_string);
 460 
 461     mc_shell_deinit ();
 462 
 463     done_key ();
 464 
 465 #ifdef USE_INTERNAL_EDIT
 466     if (macros_list != NULL)
 467     {
 468         guint i;
 469 
 470         for (i = 0; i < macros_list->len; i++)
 471         {
 472             macros_t *macros;
 473 
 474             macros = &g_array_index (macros_list, struct macros_t, i);
 475             if (macros != NULL && macros->macro != NULL)
 476                 (void) g_array_free (macros->macro, TRUE);
 477         }
 478         (void) g_array_free (macros_list, TRUE);
 479     }
 480 #endif /* USE_INTERNAL_EDIT */
 481 
 482     str_uninit_strings ();
 483 
 484     if (mc_global.mc_run_mode != MC_RUN_EDITOR)
 485         g_free (mc_run_param0);
 486     else
 487         g_list_free_full ((GList *) mc_run_param0, (GDestroyNotify) mcedit_arg_free);
 488 
 489     g_free (mc_run_param1);
 490     g_free (saved_other_dir);
 491 
 492     mc_config_deinit_config_paths ();
 493 
 494     (void) mc_event_deinit (&mcerror);
 495     if (mcerror != NULL)
 496     {
 497         fprintf (stderr, _("\nFailed while close:\n%s\n"), mcerror->message);
 498         g_error_free (mcerror);
 499         exit_code = EXIT_FAILURE;
 500     }
 501 
 502     mc_timer_destroy (mc_global.timer);
 503 
 504     (void) putchar ('\n');      /* Hack to make shell's prompt start at left of screen */
 505 
 506     return exit_code;
 507 }
 508 
 509 /* --------------------------------------------------------------------------------------------- */

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