execute.c 13 KB

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