execute.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. Execution routines for GNU Midnight Commander
  3. Copyright (C) 2003, 2004, 2005, 2007, 2011
  4. The Free Software Foundation, Inc.
  5. This file is part of the Midnight Commander.
  6. The Midnight Commander is free software: you can redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software Foundation, either version 3 of the License,
  9. or (at your option) any later version.
  10. The Midnight Commander is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. 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, see <http://www.gnu.org/licenses/>.
  16. */
  17. /** \file execute.c
  18. * \brief Source: execution routines
  19. */
  20. #include <config.h>
  21. #include <signal.h>
  22. #include <sys/stat.h>
  23. #include <sys/time.h>
  24. #include "lib/global.h"
  25. #include "lib/tty/tty.h"
  26. #include "lib/tty/key.h"
  27. #include "lib/tty/win.h"
  28. #include "lib/vfs/vfs.h"
  29. #include "lib/mcconfig.h"
  30. #include "lib/util.h"
  31. #include "lib/widget.h"
  32. #include "filemanager/midnight.h"
  33. #include "filemanager/layout.h" /* use_dash() */
  34. #include "consaver/cons.saver.h"
  35. #include "subshell.h"
  36. #include "setup.h" /* clear_before_exec */
  37. #include "execute.h"
  38. /*** global variables ****************************************************************************/
  39. int pause_after_run = pause_on_dumb_terminals;
  40. /*** file scope macro definitions ****************************************************************/
  41. /*** file scope type declarations ****************************************************************/
  42. /*** file scope variables ************************************************************************/
  43. /*** file scope functions ************************************************************************/
  44. /* --------------------------------------------------------------------------------------------- */
  45. static void
  46. edition_post_exec (void)
  47. {
  48. do_enter_ca_mode ();
  49. /* FIXME: Missing on slang endwin? */
  50. tty_reset_prog_mode ();
  51. tty_flush_input ();
  52. tty_keypad (TRUE);
  53. tty_raw_mode ();
  54. channels_up ();
  55. enable_mouse ();
  56. if (mc_global.tty.alternate_plus_minus)
  57. application_keypad_mode ();
  58. }
  59. /* --------------------------------------------------------------------------------------------- */
  60. static void
  61. edition_pre_exec (void)
  62. {
  63. if (clear_before_exec)
  64. clr_scr ();
  65. else
  66. {
  67. if (!(mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag))
  68. printf ("\n\n");
  69. }
  70. channels_down ();
  71. disable_mouse ();
  72. tty_reset_shell_mode ();
  73. tty_keypad (FALSE);
  74. tty_reset_screen ();
  75. numeric_keypad_mode ();
  76. /* on xterms: maybe endwin did not leave the terminal on the shell
  77. * screen page: do it now.
  78. *
  79. * Do not move this before endwin: in some systems rmcup includes
  80. * a call to clear screen, so it will end up clearing the shell screen.
  81. */
  82. do_exit_ca_mode ();
  83. }
  84. /* --------------------------------------------------------------------------------------------- */
  85. #ifdef HAVE_SUBSHELL_SUPPORT
  86. static void
  87. do_possible_cd (const vfs_path_t * new_dir_vpath)
  88. {
  89. if (!do_cd (new_dir_vpath, cd_exact))
  90. message (D_ERROR, _("Warning"),
  91. _("The Commander can't change to the directory that\n"
  92. "the subshell claims you are in. Perhaps you have\n"
  93. "deleted your working directory, or given yourself\n"
  94. "extra access permissions with the \"su\" command?"));
  95. }
  96. #endif /* HAVE_SUBSHELL_SUPPORT */
  97. /* --------------------------------------------------------------------------------------------- */
  98. static void
  99. do_execute (const char *lc_shell, const char *command, int flags)
  100. {
  101. #ifdef HAVE_SUBSHELL_SUPPORT
  102. vfs_path_t *new_dir_vpath = NULL;
  103. #endif /* HAVE_SUBSHELL_SUPPORT */
  104. vfs_path_t *old_vfs_dir_vpath = NULL;
  105. if (!vfs_current_is_local ())
  106. old_vfs_dir_vpath = vfs_path_clone (vfs_get_raw_current_dir ());
  107. if (mc_global.mc_run_mode == MC_RUN_FULL)
  108. save_cwds_stat ();
  109. pre_exec ();
  110. if (mc_global.tty.console_flag != '\0')
  111. handle_console (CONSOLE_RESTORE);
  112. if (!mc_global.tty.use_subshell && command && !(flags & EXECUTE_INTERNAL))
  113. {
  114. printf ("%s%s\n", mc_prompt, command);
  115. fflush (stdout);
  116. }
  117. #ifdef HAVE_SUBSHELL_SUPPORT
  118. if (mc_global.tty.use_subshell && !(flags & EXECUTE_INTERNAL))
  119. {
  120. do_update_prompt ();
  121. /* We don't care if it died, higher level takes care of this */
  122. invoke_subshell (command, VISIBLY, old_vfs_dir_vpath != NULL ? NULL : &new_dir_vpath);
  123. }
  124. else
  125. #endif /* HAVE_SUBSHELL_SUPPORT */
  126. my_system (flags, lc_shell, command);
  127. if (!(flags & EXECUTE_INTERNAL))
  128. {
  129. if ((pause_after_run == pause_always
  130. || (pause_after_run == pause_on_dumb_terminals && !mc_global.tty.xterm_flag
  131. && mc_global.tty.console_flag == '\0')) && quit == 0
  132. #ifdef HAVE_SUBSHELL_SUPPORT
  133. && subshell_state != RUNNING_COMMAND
  134. #endif /* HAVE_SUBSHELL_SUPPORT */
  135. )
  136. {
  137. printf (_("Press any key to continue..."));
  138. fflush (stdout);
  139. tty_raw_mode ();
  140. get_key_code (0);
  141. printf ("\r\n");
  142. fflush (stdout);
  143. }
  144. if (mc_global.tty.console_flag != '\0')
  145. {
  146. if (output_lines && mc_global.keybar_visible)
  147. {
  148. putchar ('\n');
  149. fflush (stdout);
  150. }
  151. }
  152. }
  153. if (mc_global.tty.console_flag != '\0')
  154. handle_console (CONSOLE_SAVE);
  155. edition_post_exec ();
  156. #ifdef HAVE_SUBSHELL_SUPPORT
  157. if (new_dir_vpath != NULL)
  158. {
  159. do_possible_cd (new_dir_vpath);
  160. vfs_path_free (new_dir_vpath);
  161. }
  162. #endif /* HAVE_SUBSHELL_SUPPORT */
  163. if (old_vfs_dir_vpath != NULL)
  164. {
  165. mc_chdir (old_vfs_dir_vpath);
  166. vfs_path_free (old_vfs_dir_vpath);
  167. }
  168. if (mc_global.mc_run_mode == MC_RUN_FULL)
  169. {
  170. update_panels (UP_OPTIMIZE, UP_KEEPSEL);
  171. update_xterm_title_path ();
  172. }
  173. do_refresh ();
  174. use_dash (TRUE);
  175. }
  176. /* --------------------------------------------------------------------------------------------- */
  177. static void
  178. do_suspend_cmd (void)
  179. {
  180. pre_exec ();
  181. if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
  182. handle_console (CONSOLE_RESTORE);
  183. #ifdef SIGTSTP
  184. {
  185. struct sigaction sigtstp_action;
  186. /* Make sure that the SIGTSTP below will suspend us directly,
  187. without calling ncurses' SIGTSTP handler; we *don't* want
  188. ncurses to redraw the screen immediately after the SIGCONT */
  189. sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
  190. kill (getpid (), SIGTSTP);
  191. /* Restore previous SIGTSTP action */
  192. sigaction (SIGTSTP, &sigtstp_action, NULL);
  193. }
  194. #endif /* SIGTSTP */
  195. if (mc_global.tty.console_flag != '\0' && !mc_global.tty.use_subshell)
  196. handle_console (CONSOLE_SAVE);
  197. edition_post_exec ();
  198. }
  199. /* --------------------------------------------------------------------------------------------- */
  200. /*** public functions ****************************************************************************/
  201. /* --------------------------------------------------------------------------------------------- */
  202. /** Set up the terminal before executing a program */
  203. void
  204. pre_exec (void)
  205. {
  206. use_dash (FALSE);
  207. edition_pre_exec ();
  208. }
  209. /* --------------------------------------------------------------------------------------------- */
  210. /** Hide the terminal after executing a program */
  211. void
  212. post_exec (void)
  213. {
  214. edition_post_exec ();
  215. use_dash (TRUE);
  216. repaint_screen ();
  217. }
  218. /* --------------------------------------------------------------------------------------------- */
  219. /* Executes a command */
  220. void
  221. shell_execute (const char *command, int flags)
  222. {
  223. char *cmd = NULL;
  224. if (flags & EXECUTE_HIDE)
  225. {
  226. cmd = g_strconcat (" ", command, (char *) NULL);
  227. flags ^= EXECUTE_HIDE;
  228. }
  229. #ifdef HAVE_SUBSHELL_SUPPORT
  230. if (mc_global.tty.use_subshell)
  231. if (subshell_state == INACTIVE)
  232. do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
  233. else
  234. message (D_ERROR, MSG_ERROR, _("The shell is already running a command"));
  235. else
  236. #endif /* HAVE_SUBSHELL_SUPPORT */
  237. do_execute (shell, cmd ? cmd : command, flags | EXECUTE_AS_SHELL);
  238. g_free (cmd);
  239. }
  240. /* --------------------------------------------------------------------------------------------- */
  241. void
  242. exec_shell (void)
  243. {
  244. do_execute (shell, 0, 0);
  245. }
  246. /* --------------------------------------------------------------------------------------------- */
  247. void
  248. toggle_panels (void)
  249. {
  250. #ifdef HAVE_SUBSHELL_SUPPORT
  251. vfs_path_t *new_dir_vpath = NULL;
  252. vfs_path_t **new_dir_p;
  253. #endif /* HAVE_SUBSHELL_SUPPORT */
  254. channels_down ();
  255. disable_mouse ();
  256. if (clear_before_exec)
  257. clr_scr ();
  258. if (mc_global.tty.alternate_plus_minus)
  259. numeric_keypad_mode ();
  260. #ifndef HAVE_SLANG
  261. /* With slang we don't want any of this, since there
  262. * is no raw_mode supported
  263. */
  264. tty_reset_shell_mode ();
  265. #endif /* !HAVE_SLANG */
  266. tty_noecho ();
  267. tty_keypad (FALSE);
  268. tty_reset_screen ();
  269. do_exit_ca_mode ();
  270. tty_raw_mode ();
  271. if (mc_global.tty.console_flag != '\0')
  272. handle_console (CONSOLE_RESTORE);
  273. #ifdef HAVE_SUBSHELL_SUPPORT
  274. if (mc_global.tty.use_subshell)
  275. {
  276. new_dir_p = vfs_current_is_local () ? &new_dir_vpath : NULL;
  277. invoke_subshell (NULL, VISIBLY, new_dir_p);
  278. }
  279. else
  280. #endif /* HAVE_SUBSHELL_SUPPORT */
  281. {
  282. if (output_starts_shell)
  283. {
  284. fprintf (stderr, _("Type `exit' to return to the Midnight Commander"));
  285. fprintf (stderr, "\n\r\n\r");
  286. my_system (EXECUTE_INTERNAL, shell, NULL);
  287. }
  288. else
  289. get_key_code (0);
  290. }
  291. if (mc_global.tty.console_flag != '\0')
  292. handle_console (CONSOLE_SAVE);
  293. do_enter_ca_mode ();
  294. tty_reset_prog_mode ();
  295. tty_keypad (TRUE);
  296. /* Prevent screen flash when user did 'exit' or 'logout' within
  297. subshell */
  298. if ((quit & SUBSHELL_EXIT) != 0)
  299. {
  300. /* User did `exit' or `logout': quit MC */
  301. if (quiet_quit_cmd ())
  302. return;
  303. quit = 0;
  304. #ifdef HAVE_SUBSHELL_SUPPORT
  305. /* restart subshell */
  306. if (mc_global.tty.use_subshell)
  307. init_subshell ();
  308. #endif /* HAVE_SUBSHELL_SUPPORT */
  309. }
  310. enable_mouse ();
  311. channels_up ();
  312. if (mc_global.tty.alternate_plus_minus)
  313. application_keypad_mode ();
  314. #ifdef HAVE_SUBSHELL_SUPPORT
  315. if (mc_global.tty.use_subshell)
  316. {
  317. do_load_prompt ();
  318. if (new_dir_vpath != NULL)
  319. do_possible_cd (new_dir_vpath);
  320. if (mc_global.tty.console_flag != '\0' && output_lines)
  321. show_console_contents (output_start_y,
  322. LINES - mc_global.keybar_visible - output_lines -
  323. 1, LINES - mc_global.keybar_visible - 1);
  324. }
  325. vfs_path_free (new_dir_vpath);
  326. #endif /* HAVE_SUBSHELL_SUPPORT */
  327. if (mc_global.mc_run_mode == MC_RUN_FULL)
  328. {
  329. update_panels (UP_OPTIMIZE, UP_KEEPSEL);
  330. update_xterm_title_path ();
  331. }
  332. repaint_screen ();
  333. }
  334. /* --------------------------------------------------------------------------------------------- */
  335. /* event callback */
  336. gboolean
  337. execute_suspend (const gchar * event_group_name, const gchar * event_name,
  338. gpointer init_data, gpointer data)
  339. {
  340. (void) event_group_name;
  341. (void) event_name;
  342. (void) init_data;
  343. (void) data;
  344. if (mc_global.mc_run_mode == MC_RUN_FULL)
  345. save_cwds_stat ();
  346. do_suspend_cmd ();
  347. if (mc_global.mc_run_mode == MC_RUN_FULL)
  348. update_panels (UP_OPTIMIZE, UP_KEEPSEL);
  349. do_refresh ();
  350. return TRUE;
  351. }
  352. /* --------------------------------------------------------------------------------------------- */
  353. /**
  354. * Execute command on a filename that can be on VFS.
  355. * Errors are reported to the user.
  356. */
  357. void
  358. execute_with_vfs_arg (const char *command, const vfs_path_t * filename_vpath)
  359. {
  360. struct stat st;
  361. time_t mtime;
  362. vfs_path_t *localcopy_vpath;
  363. /* Simplest case, this file is local */
  364. if (filename_vpath == NULL || vfs_file_is_local (filename_vpath))
  365. {
  366. do_execute (command, vfs_path_get_last_path_str (filename_vpath), EXECUTE_INTERNAL);
  367. return;
  368. }
  369. /* FIXME: Creation of new files on VFS is not supported */
  370. if (vfs_path_len (filename_vpath) == 0)
  371. return;
  372. localcopy_vpath = mc_getlocalcopy (filename_vpath);
  373. if (localcopy_vpath == NULL)
  374. {
  375. char *filename;
  376. filename = vfs_path_to_str (filename_vpath);
  377. message (D_ERROR, MSG_ERROR, _("Cannot fetch a local copy of %s"), filename);
  378. g_free (filename);
  379. return;
  380. }
  381. /*
  382. * filename can be an entry on panel, it can be changed by executing
  383. * the command, so make a copy. Smarter VFS code would make the code
  384. * below unnecessary.
  385. */
  386. mc_stat (localcopy_vpath, &st);
  387. mtime = st.st_mtime;
  388. do_execute (command, vfs_path_get_last_path_str (localcopy_vpath), EXECUTE_INTERNAL);
  389. mc_stat (localcopy_vpath, &st);
  390. mc_ungetlocalcopy (filename_vpath, localcopy_vpath, mtime != st.st_mtime);
  391. vfs_path_free (localcopy_vpath);
  392. }
  393. /* --------------------------------------------------------------------------------------------- */