Merge branch '2123_crash_while_copy'
[midnight-commander.git] / src / execute.c
blob8e40667f97ed3fb60805fd679696325e2f9831bb
1 /* Execution routines for GNU Midnight Commander
2 Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /** \file execute.c
19 * \brief Source: execution routines
22 #include <config.h>
24 #include <signal.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
28 #include "lib/global.h"
30 #include "lib/tty/tty.h"
31 #include "lib/tty/key.h"
32 #include "lib/tty/win.h"
34 #include "main.h"
35 #include "consaver/cons.saver.h"
36 #include "subshell.h"
37 #include "layout.h"
38 #include "dialog.h"
39 #include "wtools.h"
40 #include "panel.h" /* update_panels() */
41 #include "execute.h"
42 #include "lib/vfs/mc-vfs/vfs.h"
45 static void
46 edition_post_exec (void)
48 do_enter_ca_mode ();
50 /* FIXME: Missing on slang endwin? */
51 tty_reset_prog_mode ();
52 tty_flush_input ();
54 tty_keypad (TRUE);
55 tty_raw_mode ();
56 channels_up ();
57 enable_mouse ();
58 if (alternate_plus_minus)
59 application_keypad_mode ();
63 static void
64 edition_pre_exec (void)
66 if (clear_before_exec)
67 clr_scr ();
68 else
70 if (!(console_flag || xterm_flag))
71 printf ("\n\n");
74 channels_down ();
75 disable_mouse ();
77 tty_reset_shell_mode ();
78 tty_keypad (FALSE);
79 tty_reset_screen ();
81 numeric_keypad_mode ();
83 /* on xterms: maybe endwin did not leave the terminal on the shell
84 * screen page: do it now.
86 * Do not move this before endwin: in some systems rmcup includes
87 * a call to clear screen, so it will end up clearing the shell screen.
89 do_exit_ca_mode ();
93 /* Set up the terminal before executing a program */
94 static void
95 pre_exec (void)
97 use_dash (0);
98 edition_pre_exec ();
102 #ifdef HAVE_SUBSHELL_SUPPORT
103 static void
104 do_possible_cd (const char *new_dir)
106 if (!do_cd (new_dir, cd_exact))
107 message (D_ERROR, _("Warning"),
108 _("The Commander can't change to the directory that\n"
109 "the subshell claims you are in. Perhaps you have\n"
110 "deleted your working directory, or given yourself\n"
111 "extra access permissions with the \"su\" command?"));
113 #endif /* HAVE_SUBSHELL_SUPPORT */
115 static void
116 do_execute (const char *lc_shell, const char *command, int flags)
118 #ifdef HAVE_SUBSHELL_SUPPORT
119 char *new_dir = NULL;
120 #endif /* HAVE_SUBSHELL_SUPPORT */
122 #ifdef ENABLE_VFS
123 char *old_vfs_dir = 0;
125 if (!vfs_current_is_local ())
126 old_vfs_dir = g_strdup (vfs_get_current_dir ());
127 #endif /* ENABLE_VFS */
129 if (mc_run_mode == MC_RUN_FULL)
130 save_cwds_stat ();
131 pre_exec ();
132 if (console_flag)
133 handle_console (CONSOLE_RESTORE);
135 if (!use_subshell && command && !(flags & EXECUTE_INTERNAL))
137 printf ("%s%s\n", mc_prompt, command);
138 fflush (stdout);
140 #ifdef HAVE_SUBSHELL_SUPPORT
141 if (use_subshell && !(flags & EXECUTE_INTERNAL))
143 do_update_prompt ();
145 /* We don't care if it died, higher level takes care of this */
146 #ifdef ENABLE_VFS
147 invoke_subshell (command, VISIBLY, old_vfs_dir ? NULL : &new_dir);
148 #else
149 invoke_subshell (command, VISIBLY, &new_dir);
150 #endif /* !ENABLE_VFS */
152 else
153 #endif /* HAVE_SUBSHELL_SUPPORT */
154 my_system (flags, lc_shell, command);
156 if (!(flags & EXECUTE_INTERNAL))
158 if ((pause_after_run == pause_always
159 || (pause_after_run == pause_on_dumb_terminals && !xterm_flag
160 && !console_flag)) && !quit
161 #ifdef HAVE_SUBSHELL_SUPPORT
162 && subshell_state != RUNNING_COMMAND
163 #endif /* HAVE_SUBSHELL_SUPPORT */
166 printf (_("Press any key to continue..."));
167 fflush (stdout);
168 tty_raw_mode ();
169 get_key_code (0);
170 printf ("\r\n");
171 fflush (stdout);
173 if (console_flag)
175 if (output_lines && keybar_visible)
177 putchar ('\n');
178 fflush (stdout);
183 if (console_flag)
184 handle_console (CONSOLE_SAVE);
185 edition_post_exec ();
187 #ifdef HAVE_SUBSHELL_SUPPORT
188 if (new_dir)
189 do_possible_cd (new_dir);
191 #endif /* HAVE_SUBSHELL_SUPPORT */
193 #ifdef ENABLE_VFS
194 if (old_vfs_dir)
196 mc_chdir (old_vfs_dir);
197 g_free (old_vfs_dir);
199 #endif /* ENABLE_VFS */
201 if (mc_run_mode == MC_RUN_FULL)
203 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
204 update_xterm_title_path ();
207 do_refresh ();
208 use_dash (TRUE);
212 /* Executes a command */
213 void
214 shell_execute (const char *command, int flags)
216 char *cmd = NULL;
218 if (flags & EXECUTE_HIDE)
220 cmd = g_strconcat (" ", command, (char *) NULL);
221 flags ^= EXECUTE_HIDE;
224 #ifdef HAVE_SUBSHELL_SUPPORT
225 if (use_subshell)
226 if (subshell_state == INACTIVE)
227 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
228 else
229 message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
230 else
231 #endif /* HAVE_SUBSHELL_SUPPORT */
232 do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
234 g_free (cmd);
238 void
239 exec_shell (void)
241 do_execute (shell, 0, 0);
245 void
246 toggle_panels (void)
248 #ifdef HAVE_SUBSHELL_SUPPORT
249 char *new_dir = NULL;
250 char **new_dir_p;
251 #endif /* HAVE_SUBSHELL_SUPPORT */
253 channels_down ();
254 disable_mouse ();
255 if (clear_before_exec)
256 clr_scr ();
257 if (alternate_plus_minus)
258 numeric_keypad_mode ();
259 #ifndef HAVE_SLANG
260 /* With slang we don't want any of this, since there
261 * is no raw_mode supported
263 tty_reset_shell_mode ();
264 #endif /* !HAVE_SLANG */
265 tty_noecho ();
266 tty_keypad (FALSE);
267 tty_reset_screen ();
268 do_exit_ca_mode ();
269 tty_raw_mode ();
270 if (console_flag)
271 handle_console (CONSOLE_RESTORE);
273 #ifdef HAVE_SUBSHELL_SUPPORT
274 if (use_subshell)
276 new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
277 invoke_subshell (NULL, VISIBLY, new_dir_p);
279 else
280 #endif /* HAVE_SUBSHELL_SUPPORT */
282 if (output_starts_shell)
284 fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
285 fprintf (stderr, "\n\r\n\r");
287 my_system (EXECUTE_INTERNAL, shell, NULL);
289 else
290 get_key_code (0);
293 if (console_flag)
294 handle_console (CONSOLE_SAVE);
296 do_enter_ca_mode ();
298 tty_reset_prog_mode ();
299 tty_keypad (TRUE);
301 /* Prevent screen flash when user did 'exit' or 'logout' within
302 subshell */
303 if ((quit & SUBSHELL_EXIT) != 0)
305 /* User did `exit' or `logout': quit MC */
306 if (quiet_quit_cmd ())
307 return;
309 quit = 0;
310 #ifdef HAVE_SUBSHELL_SUPPORT
311 /* restart subshell */
312 if (use_subshell)
313 init_subshell ();
314 #endif /* HAVE_SUBSHELL_SUPPORT */
317 enable_mouse ();
318 channels_up ();
319 if (alternate_plus_minus)
320 application_keypad_mode ();
322 #ifdef HAVE_SUBSHELL_SUPPORT
323 if (use_subshell)
325 load_prompt (0, 0);
326 if (new_dir)
327 do_possible_cd (new_dir);
328 if (console_flag && output_lines)
329 show_console_contents (output_start_y,
330 LINES - keybar_visible - output_lines -
331 1, LINES - keybar_visible - 1);
333 #endif /* HAVE_SUBSHELL_SUPPORT */
335 if (mc_run_mode == MC_RUN_FULL)
337 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
338 update_xterm_title_path ();
340 repaint_screen ();
344 static void
345 do_suspend_cmd (void)
347 pre_exec ();
349 if (console_flag && !use_subshell)
350 handle_console (CONSOLE_RESTORE);
352 #ifdef SIGTSTP
354 struct sigaction sigtstp_action;
356 /* Make sure that the SIGTSTP below will suspend us directly,
357 without calling ncurses' SIGTSTP handler; we *don't* want
358 ncurses to redraw the screen immediately after the SIGCONT */
359 sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
361 kill (getpid (), SIGTSTP);
363 /* Restore previous SIGTSTP action */
364 sigaction (SIGTSTP, &sigtstp_action, NULL);
366 #endif /* SIGTSTP */
368 if (console_flag && !use_subshell)
369 handle_console (CONSOLE_SAVE);
371 edition_post_exec ();
375 void
376 suspend_cmd (void)
378 if (mc_run_mode == MC_RUN_FULL)
379 save_cwds_stat ();
380 do_suspend_cmd ();
381 if (mc_run_mode == MC_RUN_FULL)
382 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
383 do_refresh ();
388 * Execute command on a filename that can be on VFS.
389 * Errors are reported to the user.
391 void
392 execute_with_vfs_arg (const char *command, const char *filename)
394 char *localcopy;
395 char *fn;
396 struct stat st;
397 time_t mtime;
399 /* Simplest case, this file is local */
400 if (!filename || vfs_file_is_local (filename))
402 fn = vfs_canon_and_translate (filename);
403 do_execute (command, fn, EXECUTE_INTERNAL);
404 g_free (fn);
405 return;
408 /* FIXME: Creation of new files on VFS is not supported */
409 if (!*filename)
410 return;
412 localcopy = mc_getlocalcopy (filename);
413 if (localcopy == NULL)
415 message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
416 return;
420 * filename can be an entry on panel, it can be changed by executing
421 * the command, so make a copy. Smarter VFS code would make the code
422 * below unnecessary.
424 fn = g_strdup (filename);
425 mc_stat (localcopy, &st);
426 mtime = st.st_mtime;
427 do_execute (command, localcopy, EXECUTE_INTERNAL);
428 mc_stat (localcopy, &st);
429 mc_ungetlocalcopy (fn, localcopy, mtime != st.st_mtime);
430 g_free (localcopy);
431 g_free (fn);