Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * Execute external programs |
4 | | * |
5 | | * @authors |
6 | | * Copyright (C) 1996-2000,2013 Michael R. Elkins <me@mutt.org> |
7 | | * Copyright (C) 2017-2023 Richard Russon <rich@flatcap.org> |
8 | | * |
9 | | * @copyright |
10 | | * This program is free software: you can redistribute it and/or modify it under |
11 | | * the terms of the GNU General Public License as published by the Free Software |
12 | | * Foundation, either version 2 of the License, or (at your option) any later |
13 | | * version. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
18 | | * details. |
19 | | * |
20 | | * You should have received a copy of the GNU General Public License along with |
21 | | * this program. If not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | /** |
25 | | * @page neo_system Execute external programs |
26 | | * |
27 | | * Execute external programs |
28 | | */ |
29 | | |
30 | | #include "config.h" |
31 | | #include <signal.h> |
32 | | #include <stdbool.h> |
33 | | #include <stdlib.h> |
34 | | #include <sys/types.h> |
35 | | #include <sys/wait.h> // IWYU pragma: keep |
36 | | #include <unistd.h> |
37 | | #include "mutt/lib.h" |
38 | | #include "core/lib.h" |
39 | | #include "imap/lib.h" |
40 | | #include "protos.h" |
41 | | |
42 | | /** |
43 | | * mutt_system - Run an external command |
44 | | * @param cmd Command and arguments |
45 | | * @retval -1 Error |
46 | | * @retval >=0 Success (command's return code) |
47 | | * |
48 | | * Fork and run an external command with arguments. |
49 | | * |
50 | | * @note This function won't return until the command finishes. |
51 | | */ |
52 | | int mutt_system(const char *cmd) |
53 | 0 | { |
54 | 0 | int rc = -1; |
55 | 0 | struct sigaction act = { 0 }; |
56 | 0 | struct sigaction oldtstp = { 0 }; |
57 | 0 | struct sigaction oldcont = { 0 }; |
58 | 0 | pid_t pid; |
59 | |
|
60 | 0 | if (!cmd || (*cmd == '\0')) |
61 | 0 | return 0; |
62 | | |
63 | | /* must ignore SIGINT and SIGQUIT */ |
64 | | |
65 | 0 | mutt_sig_block_system(); |
66 | |
|
67 | 0 | act.sa_handler = SIG_DFL; |
68 | | /* we want to restart the waitpid() below */ |
69 | 0 | #ifdef SA_RESTART |
70 | 0 | act.sa_flags = SA_RESTART; |
71 | 0 | #endif |
72 | 0 | sigemptyset(&act.sa_mask); |
73 | 0 | sigaction(SIGTSTP, &act, &oldtstp); |
74 | 0 | sigaction(SIGCONT, &act, &oldcont); |
75 | |
|
76 | 0 | pid = fork(); |
77 | 0 | if (pid == 0) |
78 | 0 | { |
79 | 0 | act.sa_flags = 0; |
80 | |
|
81 | 0 | mutt_sig_unblock_system(false); |
82 | 0 | mutt_sig_reset_child_signals(); |
83 | |
|
84 | 0 | execle(EXEC_SHELL, "sh", "-c", cmd, NULL, NeoMutt->env); |
85 | 0 | _exit(127); /* execl error */ |
86 | 0 | } |
87 | 0 | else if (pid != -1) |
88 | 0 | { |
89 | 0 | rc = imap_wait_keep_alive(pid); |
90 | 0 | } |
91 | | |
92 | 0 | sigaction(SIGCONT, &oldcont, NULL); |
93 | 0 | sigaction(SIGTSTP, &oldtstp, NULL); |
94 | | |
95 | | /* reset SIGINT, SIGQUIT and SIGCHLD */ |
96 | 0 | mutt_sig_unblock_system(true); |
97 | |
|
98 | 0 | rc = (pid != -1) ? (WIFEXITED(rc) ? WEXITSTATUS(rc) : -1) : -1; |
99 | |
|
100 | 0 | return rc; |
101 | 0 | } |