NeoMutt  2025-12-11-980-ge38c27
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] = { 0 };
66 int pout[2] = { 0 };
67 int perr[2] = { 0 };
68 int pid;
69
70 /* Create pipes for each requested I/O stream (stdin, stdout, stderr).
71 * On failure, clean up any already-created pipes before returning. */
72 if (fp_in)
73 {
74 *fp_in = NULL;
75 if (pipe(pin) == -1)
76 return -1;
77 }
78
79 if (fp_out)
80 {
81 *fp_out = NULL;
82 if (pipe(pout) == -1)
83 {
84 if (fp_in)
85 {
86 close(pin[0]);
87 close(pin[1]);
88 }
89 return -1;
90 }
91 }
92
93 if (fp_err)
94 {
95 *fp_err = NULL;
96 if (pipe(perr) == -1)
97 {
98 if (fp_in)
99 {
100 close(pin[0]);
101 close(pin[1]);
102 }
103 if (fp_out)
104 {
105 close(pout[0]);
106 close(pout[1]);
107 }
108 return -1;
109 }
110 }
111
112 /* Block signals around fork to prevent child from inheriting pending signals */
114
115 pid = fork();
116 if (pid == 0)
117 {
118 /* Child process: redirect pipe ends to stdin/stdout/stderr via dup2(),
119 * or use the caller-supplied file descriptors as fallback */
122
123 if (fp_in)
124 {
125 close(pin[1]);
126 dup2(pin[0], 0);
127 close(pin[0]);
128 }
129 else if (fdin != -1)
130 {
131 dup2(fdin, 0);
132 close(fdin);
133 }
134
135 if (fp_out)
136 {
137 close(pout[0]);
138 dup2(pout[1], 1);
139 close(pout[1]);
140 }
141 else if (fdout != -1)
142 {
143 dup2(fdout, 1);
144 close(fdout);
145 }
146
147 if (fp_err)
148 {
149 close(perr[0]);
150 dup2(perr[1], 2);
151 close(perr[1]);
152 }
153 else if (fderr != -1)
154 {
155 dup2(fderr, 2);
156 close(fderr);
157 }
158
159 execle(EXEC_SHELL, "sh", "-c", cmd, NULL, envlist);
160 _exit(127);
161 }
162 else if (pid == -1)
163 {
164 /* Fork failed: clean up all pipe file descriptors */
166
167 if (fp_in)
168 {
169 close(pin[0]);
170 close(pin[1]);
171 }
172
173 if (fp_out)
174 {
175 close(pout[0]);
176 close(pout[1]);
177 }
178
179 if (fp_err)
180 {
181 close(perr[0]);
182 close(perr[1]);
183 }
184
185 return -1;
186 }
187
188 /* Parent process: close the child's end of each pipe and wrap
189 * the parent's end in a FILE stream for the caller */
190 if (fp_out)
191 {
192 close(pout[1]);
193 *fp_out = fdopen(pout[0], "r");
194 }
195
196 if (fp_in)
197 {
198 close(pin[0]);
199 *fp_in = fdopen(pin[1], "w");
200 }
201
202 if (fp_err)
203 {
204 close(perr[1]);
205 *fp_err = fdopen(perr[0], "r");
206 }
207
208 return pid;
209}
210
220pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
221{
222 return filter_create_fd(cmd, fp_in, fp_out, fp_err, -1, -1, -1, envlist);
223}
224
231int filter_wait(pid_t pid)
232{
233 int rc = 0;
234
235 waitpid(pid, &rc, 0);
237 rc = WIFEXITED(rc) ? WEXITSTATUS(rc) : -1;
238
239 return rc;
240}
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
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:220
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