Don't exit after migration of configuration files.
[midnight-commander.git] / src / main.c
blob6b014bd7fb1f71e2e3ae5b643e5e786a402c7e8e
1 /*
2 Main program for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5 2003, 2004, 2005, 2006, 2007, 2009, 2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1996, 1997
10 Janne Kukonlehto, 1994, 1995
11 Norbert Warmuth, 1997
13 This file is part of the Midnight Commander.
15 The Midnight Commander is free software: you can redistribute it
16 and/or modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation, either version 3 of the License,
18 or (at your option) any later version.
20 The Midnight Commander is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 /** \file main.c
30 * \brief Source: this is a main module
33 #include <config.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <locale.h>
38 #include <pwd.h> /* for username in xterm title */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/wait.h>
43 #include <signal.h>
45 #include "lib/global.h"
47 #include "lib/event.h"
48 #include "lib/tty/tty.h"
49 #include "lib/tty/key.h" /* For init_key() */
50 #include "lib/skin.h"
51 #include "lib/filehighlight.h"
52 #include "lib/fileloc.h"
53 #include "lib/strutil.h"
54 #include "lib/util.h"
55 #include "lib/vfs/vfs.h" /* vfs_init(), vfs_shut() */
57 #include "filemanager/midnight.h" /* current_panel */
58 #include "filemanager/treestore.h" /* tree_store_save */
59 #include "filemanager/layout.h" /* command_prompt */
60 #include "filemanager/ext.h" /* flush_extension_file() */
61 #include "filemanager/command.h" /* cmdline */
62 #include "filemanager/panel.h" /* panalized_panel */
64 #include "vfs/plugins_init.h"
66 #include "events_init.h"
67 #include "args.h"
68 #ifdef ENABLE_SUBSHELL
69 #include "subshell.h"
70 #endif
71 #include "setup.h" /* load_setup() */
73 #ifdef HAVE_CHARSET
74 #include "lib/charsets.h"
75 #include "selcodepage.h"
76 #endif /* HAVE_CHARSET */
78 #include "consaver/cons.saver.h" /* cons_saver_pid */
80 /*** global variables ****************************************************************************/
82 /*** file scope macro definitions ****************************************************************/
84 /*** file scope type declarations ****************************************************************/
86 /*** file scope variables ************************************************************************/
88 /*** file scope functions ************************************************************************/
89 /* --------------------------------------------------------------------------------------------- */
91 static void
92 check_codeset (void)
94 const char *current_system_codepage = NULL;
96 current_system_codepage = str_detect_termencoding ();
98 #ifdef HAVE_CHARSET
100 const char *_display_codepage;
102 _display_codepage = get_codepage_id (mc_global.display_codepage);
104 if (strcmp (_display_codepage, current_system_codepage) != 0)
106 mc_global.display_codepage = get_codepage_index (current_system_codepage);
107 if (mc_global.display_codepage == -1)
108 mc_global.display_codepage = 0;
110 mc_config_set_string (mc_main_config, CONFIG_MISC_SECTION, "display_codepage",
111 cp_display);
114 #endif
116 mc_global.utf8_display = str_isutf8 (current_system_codepage);
119 /* --------------------------------------------------------------------------------------------- */
121 /** POSIX version. The only version we support. */
122 static void
123 OS_Setup (void)
125 const char *shell_env;
126 const char *datadir_env;
128 shell_env = getenv ("SHELL");
129 if ((shell_env == NULL) || (shell_env[0] == '\0'))
131 struct passwd *pwd;
132 pwd = getpwuid (geteuid ());
133 if (pwd != NULL)
134 shell = g_strdup (pwd->pw_shell);
136 else
137 shell = g_strdup (shell_env);
139 if ((shell == NULL) || (shell[0] == '\0'))
141 g_free (shell);
142 shell = g_strdup ("/bin/sh");
145 /* This is the directory, where MC was installed, on Unix this is DATADIR */
146 /* and can be overriden by the MC_DATADIR environment variable */
147 datadir_env = g_getenv ("MC_DATADIR");
148 if (datadir_env != NULL)
149 mc_global.sysconfig_dir = g_strdup (datadir_env);
150 else
151 mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
153 mc_global.share_data_dir = g_strdup (DATADIR);
155 /* Set up temporary directory */
156 mc_tmpdir ();
159 /* --------------------------------------------------------------------------------------------- */
161 static void
162 sigchld_handler_no_subshell (int sig)
164 #ifdef __linux__
165 int pid, status;
167 if (!mc_global.tty.console_flag != '\0')
168 return;
170 /* COMMENT: if it were true that after the call to handle_console(..INIT)
171 the value of mc_global.tty.console_flag never changed, we could simply not install
172 this handler at all if (!mc_global.tty.console_flag && !mc_global.tty.use_subshell). */
174 /* That comment is no longer true. We need to wait() on a sigchld
175 handler (that's at least what the tarfs code expects currently). */
177 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
179 if (pid == cons_saver_pid)
182 if (WIFSTOPPED (status))
184 /* Someone has stopped cons.saver - restart it */
185 kill (pid, SIGCONT);
187 else
189 /* cons.saver has died - disable console saving */
190 handle_console (CONSOLE_DONE);
191 mc_global.tty.console_flag = '\0';
194 /* If we got here, some other child exited; ignore it */
195 #endif /* __linux__ */
197 (void) sig;
200 /* --------------------------------------------------------------------------------------------- */
202 static void
203 init_sigchld (void)
205 struct sigaction sigchld_action;
207 sigchld_action.sa_handler =
208 #ifdef ENABLE_SUBSHELL
209 mc_global.tty.use_subshell ? sigchld_handler :
210 #endif /* ENABLE_SUBSHELL */
211 sigchld_handler_no_subshell;
213 sigemptyset (&sigchld_action.sa_mask);
215 #ifdef SA_RESTART
216 sigchld_action.sa_flags = SA_RESTART;
217 #else
218 sigchld_action.sa_flags = 0;
219 #endif /* !SA_RESTART */
221 if (sigaction (SIGCHLD, &sigchld_action, NULL) == -1)
223 #ifdef ENABLE_SUBSHELL
225 * This may happen on QNX Neutrino 6, where SA_RESTART
226 * is defined but not implemented. Fallback to no subshell.
228 mc_global.tty.use_subshell = FALSE;
229 #endif /* ENABLE_SUBSHELL */
233 /* --------------------------------------------------------------------------------------------- */
234 /*** public functions ****************************************************************************/
235 /* --------------------------------------------------------------------------------------------- */
238 main (int argc, char *argv[])
240 GError *error = NULL;
241 gboolean config_migrated = FALSE;
242 char *config_migrate_msg;
243 int exit_code = EXIT_FAILURE;
245 /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
246 #ifdef HAVE_SETLOCALE
247 (void) setlocale (LC_ALL, "");
248 #endif
249 (void) bindtextdomain (PACKAGE, LOCALEDIR);
250 (void) textdomain (PACKAGE);
252 /* do this before args parsing */
253 str_init_strings (NULL);
255 if (!mc_args_parse (&argc, &argv, "mc", &error))
257 startup_exit_falure:
258 fprintf (stderr, _("Failed to run:\n%s\n"), error->message);
259 g_error_free (error);
260 g_free (shell);
261 startup_exit_ok:
262 str_uninit_strings ();
263 return exit_code;
266 /* do this before mc_args_show_info () to view paths in the --datadir-info output */
267 OS_Setup ();
269 if (!g_path_is_absolute (mc_config_get_home_dir ()))
271 error = g_error_new (MC_ERROR, 0, "%s: %s", _("Home directory path is not absolute"),
272 mc_config_get_home_dir ());
273 mc_event_deinit (NULL);
274 goto startup_exit_falure;
277 if (!mc_args_show_info ())
279 exit_code = EXIT_SUCCESS;
280 goto startup_exit_ok;
283 if (!events_init (&error))
284 goto startup_exit_falure;
286 mc_config_init_config_paths (&error);
287 if (error == NULL)
288 config_migrated = mc_config_migrate_from_old_place (&error, &config_migrate_msg);
289 if (error != NULL)
291 mc_event_deinit (NULL);
292 goto startup_exit_falure;
295 vfs_init ();
296 vfs_plugins_init ();
297 vfs_setup_work_dir ();
299 /* do this after vfs initialization due to mc_setctl() call in mc_setup_by_args() */
300 if (!mc_setup_by_args (argc, argv, &error))
302 vfs_shut ();
303 mc_event_deinit (NULL);
304 goto startup_exit_falure;
307 /* check terminal type
308 * $TEMR must be set and not empty
309 * mc_global.tty.xterm_flag is used in init_key() and tty_init()
310 * Do this after mc_args_handle() where mc_args__force_xterm is set up.
312 mc_global.tty.xterm_flag = tty_check_term (mc_args__force_xterm);
314 /* NOTE: This has to be called before tty_init or whatever routine
315 calls any define_sequence */
316 init_key ();
318 /* Must be done before installing the SIGCHLD handler [[FIXME]] */
319 handle_console (CONSOLE_INIT);
321 #ifdef ENABLE_SUBSHELL
322 /* Don't use subshell when invoked as viewer or editor */
323 if (mc_global.mc_run_mode != MC_RUN_FULL)
324 mc_global.tty.use_subshell = FALSE;
326 if (mc_global.tty.use_subshell)
327 subshell_get_console_attributes ();
328 #endif /* ENABLE_SUBSHELL */
330 /* Install the SIGCHLD handler; must be done before init_subshell() */
331 init_sigchld ();
333 /* We need this, since ncurses endwin () doesn't restore the signals */
334 save_stop_handler ();
336 /* Must be done before init_subshell, to set up the terminal size: */
337 /* FIXME: Should be removed and LINES and COLS computed on subshell */
338 tty_init (!mc_args__nomouse, mc_global.tty.xterm_flag);
340 load_setup ();
342 /* start check mc_global.display_codepage and mc_global.source_codepage */
343 check_codeset ();
345 /* Removing this from the X code let's us type C-c */
346 load_key_defs ();
348 load_keymap_defs (!mc_args__nokeymap);
350 macros_list = g_array_new (TRUE, FALSE, sizeof (macros_t));
352 tty_init_colors (mc_global.tty.disable_colors, mc_args__force_colors);
354 mc_skin_init (&error);
355 if (error != NULL)
357 message (D_ERROR, _("Warning"), "%s", error->message);
358 g_error_free (error);
359 error = NULL;
362 dlg_set_default_colors ();
364 #ifdef ENABLE_SUBSHELL
365 /* Done here to ensure that the subshell doesn't */
366 /* inherit the file descriptors opened below, etc */
367 if (mc_global.tty.use_subshell)
368 init_subshell ();
370 #endif /* ENABLE_SUBSHELL */
372 /* Also done after init_subshell, to save any shell init file messages */
373 if (mc_global.tty.console_flag != '\0')
374 handle_console (CONSOLE_SAVE);
376 if (mc_global.tty.alternate_plus_minus)
377 application_keypad_mode ();
379 #ifdef ENABLE_SUBSHELL
380 if (mc_global.tty.use_subshell)
382 mc_prompt = strip_ctrl_codes (subshell_prompt);
383 if (mc_prompt == NULL)
384 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
386 else
387 #endif /* ENABLE_SUBSHELL */
388 mc_prompt = (geteuid () == 0) ? "# " : "$ ";
390 if (config_migrated)
392 message (D_ERROR, _("Warning"), "%s", config_migrate_msg);
393 g_free (config_migrate_msg);
396 /* Program main loop */
397 if (mc_global.midnight_shutdown)
398 exit_code = EXIT_SUCCESS;
399 else
400 exit_code = do_nc () ? EXIT_SUCCESS : EXIT_FAILURE;
402 /* Save the tree store */
403 (void) tree_store_save ();
405 free_keymap_defs ();
407 /* Virtual File System shutdown */
408 vfs_shut ();
410 flush_extension_file (); /* does only free memory */
412 mc_skin_deinit ();
413 tty_colors_done ();
415 tty_shutdown ();
417 done_setup ();
419 if (mc_global.tty.console_flag != '\0' && (quit & SUBSHELL_EXIT) == 0)
420 handle_console (CONSOLE_RESTORE);
421 if (mc_global.tty.alternate_plus_minus)
422 numeric_keypad_mode ();
424 (void) signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
426 if (mc_global.tty.console_flag != '\0')
427 handle_console (CONSOLE_DONE);
429 if (mc_global.mc_run_mode == MC_RUN_FULL && mc_args__last_wd_file != NULL
430 && last_wd_string != NULL && !print_last_revert)
432 int last_wd_fd;
434 last_wd_fd = open (mc_args__last_wd_file, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
435 S_IRUSR | S_IWUSR);
436 if (last_wd_fd != -1)
438 ssize_t ret1;
439 int ret2;
440 ret1 = write (last_wd_fd, last_wd_string, strlen (last_wd_string));
441 ret2 = close (last_wd_fd);
444 g_free (last_wd_string);
446 g_free (shell);
448 done_key ();
450 if (macros_list != NULL)
452 guint i;
453 macros_t *macros;
454 for (i = 0; i < macros_list->len; i++)
456 macros = &g_array_index (macros_list, struct macros_t, i);
457 if (macros != NULL && macros->macro != NULL)
458 (void) g_array_free (macros->macro, FALSE);
460 (void) g_array_free (macros_list, TRUE);
463 str_uninit_strings ();
465 if (mc_global.mc_run_mode != MC_RUN_EDITOR)
466 g_free (mc_run_param0);
467 else
469 g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
470 g_list_free ((GList *) mc_run_param0);
472 g_free (mc_run_param1);
474 mc_config_deinit_config_paths ();
476 (void) mc_event_deinit (&error);
477 if (error != NULL)
479 fprintf (stderr, _("\nFailed while close:\n%s\n"), error->message);
480 g_error_free (error);
481 exit_code = EXIT_FAILURE;
484 (void) putchar ('\n'); /* Hack to make shell's prompt start at left of screen */
486 return exit_code;
489 /* --------------------------------------------------------------------------------------------- */