NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
filter.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stdlib.h>
33#include <sys/wait.h>
34#include <unistd.h>
35#include "filter.h"
36#include "signal2.h"
37
62pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err,
63 int fdin, int fdout, int fderr, char **envlist)
64{
65 int pin[2], pout[2], perr[2], pid;
66
67 /* Create pipes for each requested I/O stream (stdin, stdout, stderr).
68 * On failure, clean up any already-created pipes before returning. */
69 if (fp_in)
70 {
71 *fp_in = NULL;
72 if (pipe(pin) == -1)
73 return -1;
74 }
75
76 if (fp_out)
77 {
78 *fp_out = NULL;
79 if (pipe(pout) == -1)
80 {
81 if (fp_in)
82 {
83 close(pin[0]);
84 close(pin[1]);
85 }
86 return -1;
87 }
88 }
89
90 if (fp_err)
91 {
92 *fp_err = NULL;
93 if (pipe(perr) == -1)
94 {
95 if (fp_in)
96 {
97 close(pin[0]);
98 close(pin[1]);
99 }
100 if (fp_out)
101 {
102 close(pout[0]);
103 close(pout[1]);
104 }
105 return -1;
106 }
107 }
108
109 /* Block signals around fork to prevent child from inheriting pending signals */
111
112 pid = fork();
113 if (pid == 0)
114 {
115 /* Child process: redirect pipe ends to stdin/stdout/stderr via dup2(),
116 * or use the caller-supplied file descriptors as fallback */
119
120 if (fp_in)
121 {
122 close(pin[1]);
123 dup2(pin[0], 0);
124 close(pin[0]);
125 }
126 else if (fdin != -1)
127 {
128 dup2(fdin, 0);
129 close(fdin);
130 }
131
132 if (fp_out)
133 {
134 close(pout[0]);
135 dup2(pout[1], 1);
136 close(pout[1]);
137 }
138 else if (fdout != -1)
139 {
140 dup2(fdout, 1);
141 close(fdout);
142 }
143
144 if (fp_err)
145 {
146 close(perr[0]);
147 dup2(perr[1], 2);
148 close(perr[1]);
149 }
150 else if (fderr != -1)
151 {
152 dup2(fderr, 2);
153 close(fderr);
154 }
155
156 execle(EXEC_SHELL, "sh", "-c", cmd, NULL, envlist);
157 _exit(127);
158 }
159 else if (pid == -1)
160 {
161 /* Fork failed: clean up all pipe file descriptors */
163
164 if (fp_in)
165 {
166 close(pin[0]);
167 close(pin[1]);
168 }
169
170 if (fp_out)
171 {
172 close(pout[0]);
173 close(pout[1]);
174 }
175
176 if (fp_err)
177 {
178 close(perr[0]);
179 close(perr[1]);
180 }
181
182 return -1;
183 }
184
185 /* Parent process: close the child's end of each pipe and wrap
186 * the parent's end in a FILE stream for the caller */
187 if (fp_out)
188 {
189 close(pout[1]);
190 *fp_out = fdopen(pout[0], "r");
191 }
192
193 if (fp_in)
194 {
195 close(pin[0]);
196 *fp_in = fdopen(pin[1], "w");
197 }
198
199 if (fp_err)
200 {
201 close(perr[1]);
202 *fp_err = fdopen(perr[0], "r");
203 }
204
205 return pid;
206}
207
217pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
218{
219 return filter_create_fd(cmd, fp_in, fp_out, fp_err, -1, -1, -1, envlist);
220}
221
228int filter_wait(pid_t pid)
229{
230 int rc = 0;
231
232 waitpid(pid, &rc, 0);
234 rc = WIFEXITED(rc) ? WEXITSTATUS(rc) : -1;
235
236 return rc;
237}
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout)
Definition filter.c:62
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:217
Pass files through external commands (filters)
#define EXEC_SHELL
Default shell to use for executing commands.
Definition filter.h:30
Signal handling.
void mutt_sig_reset_child_signals(void)
Reset ignored signals back to the default.
Definition signal.c:336
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition signal.c:260
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition signal.c:284