|
a/src/utils/execmd.cpp |
|
b/src/utils/execmd.cpp |
|
... |
|
... |
183 |
// In child process. Set up pipes and exec command.
|
183 |
// In child process. Set up pipes and exec command.
|
184 |
// This must not return. _exit() on error.
|
184 |
// This must not return. _exit() on error.
|
185 |
// *** This can be called after a vfork, so no modification of the
|
185 |
// *** This can be called after a vfork, so no modification of the
|
186 |
// process memory at all is allowed ***
|
186 |
// process memory at all is allowed ***
|
187 |
// The LOGXX calls should not be there, but they occur only after "impossible"
|
187 |
// The LOGXX calls should not be there, but they occur only after "impossible"
|
188 |
// errors, which we would most definitely want to have a hint about
|
188 |
// errors, which we would most definitely want to have a hint about.
|
|
|
189 |
//
|
|
|
190 |
// Note that any of the LOGXX calls could block on a mutex set in the
|
|
|
191 |
// father process, so that only absolutely exceptional conditions,
|
|
|
192 |
// should be logged, for debugging and post-mortem purposes
|
|
|
193 |
// If one of the calls block, the problem manifests itself by 20mn
|
|
|
194 |
// (filter timeout) of looping on "ExecCmd::doexec: selectloop
|
|
|
195 |
// returned 1', because the father is waiting on the read descriptor
|
189 |
inline void ExecCmd::dochild(const string &cmd, const char **argv,
|
196 |
inline void ExecCmd::dochild(const string &cmd, const char **argv,
|
190 |
const char **envv,
|
197 |
const char **envv,
|
191 |
bool has_input, bool has_output)
|
198 |
bool has_input, bool has_output)
|
192 |
{
|
199 |
{
|
193 |
// Start our own process group
|
200 |
// Start our own process group
|
194 |
if (setpgid(0, getpid())) {
|
201 |
if (setpgid(0, getpid())) {
|
195 |
LOGINFO(("ExecCmd::dochild: setpgid(0, %d) failed: errno %d\n",
|
202 |
LOGINFO(("ExecCmd::DOCHILD: setpgid(0, %d) failed: errno %d\n",
|
196 |
getpid(), errno));
|
203 |
getpid(), errno));
|
197 |
}
|
204 |
}
|
198 |
|
205 |
|
199 |
// Restore SIGTERM to default. Really, signal handling should be
|
206 |
// Restore SIGTERM to default. Really, signal handling should be
|
200 |
// specified when creating the execmd. Help Recoll get rid of its
|
207 |
// specified when creating the execmd. Help Recoll get rid of its
|
201 |
// filter children though. To be fixed one day... Not sure that
|
208 |
// filter children though. To be fixed one day... Not sure that
|
202 |
// all of this is needed. But an ignored sigterm and the masks are
|
209 |
// all of this is needed. But an ignored sigterm and the masks are
|
203 |
// normally inherited.
|
210 |
// normally inherited.
|
204 |
if (signal(SIGTERM, SIG_DFL) == SIG_ERR) {
|
211 |
if (signal(SIGTERM, SIG_DFL) == SIG_ERR) {
|
205 |
LOGERR(("ExecCmd::dochild: signal() failed, errno %d\n", errno));
|
212 |
//LOGERR(("ExecCmd::DOCHILD: signal() failed, errno %d\n", errno));
|
206 |
}
|
213 |
}
|
207 |
sigset_t sset;
|
214 |
sigset_t sset;
|
208 |
sigfillset(&sset);
|
215 |
sigfillset(&sset);
|
209 |
pthread_sigmask(SIG_UNBLOCK, &sset, 0);
|
216 |
pthread_sigmask(SIG_UNBLOCK, &sset, 0);
|
210 |
sigprocmask(SIG_UNBLOCK, &sset, 0);
|
217 |
sigprocmask(SIG_UNBLOCK, &sset, 0);
|
|
... |
|
... |
218 |
}
|
225 |
}
|
219 |
if (has_output) {
|
226 |
if (has_output) {
|
220 |
close(m_pipeout[0]);
|
227 |
close(m_pipeout[0]);
|
221 |
if (m_pipeout[1] != 1) {
|
228 |
if (m_pipeout[1] != 1) {
|
222 |
if (dup2(m_pipeout[1], 1) < 0) {
|
229 |
if (dup2(m_pipeout[1], 1) < 0) {
|
223 |
LOGERR(("ExecCmd::doexec: dup2(2) failed. errno %d\n", errno));
|
230 |
LOGERR(("ExecCmd::DOCHILD: dup2() failed. errno %d\n", errno));
|
224 |
}
|
231 |
}
|
225 |
if (close(m_pipeout[1]) < 0) {
|
232 |
if (close(m_pipeout[1]) < 0) {
|
226 |
LOGERR(("ExecCmd::doexec: close(2) failed. errno %d\n", errno));
|
233 |
LOGERR(("ExecCmd::DOCHILD: close() failed. errno %d\n", errno));
|
227 |
}
|
234 |
}
|
228 |
}
|
235 |
}
|
229 |
}
|
236 |
}
|
230 |
// Do we need to redirect stderr ?
|
237 |
// Do we need to redirect stderr ?
|
231 |
if (!m_stderrFile.empty()) {
|
238 |
if (!m_stderrFile.empty()) {
|
|
... |
|
... |
246 |
|
253 |
|
247 |
// Close all descriptors except 0,1,2
|
254 |
// Close all descriptors except 0,1,2
|
248 |
libclf_closefrom(3);
|
255 |
libclf_closefrom(3);
|
249 |
|
256 |
|
250 |
execve(cmd.c_str(), (char *const*)argv, (char *const*)envv);
|
257 |
execve(cmd.c_str(), (char *const*)argv, (char *const*)envv);
|
251 |
// Hu ho
|
258 |
// Hu ho. This should never happened as we checked the existence of the
|
|
|
259 |
// executable before calling dochild... Until we did this, this was
|
|
|
260 |
// the chief cause of LOG mutex deadlock
|
252 |
LOGERR(("ExecCmd::doexec: execve(%s) failed. errno %d\n", cmd.c_str(),
|
261 |
LOGERR(("ExecCmd::DOCHILD: execve(%s) failed. errno %d\n", cmd.c_str(),
|
253 |
errno));
|
262 |
errno));
|
254 |
_exit(127);
|
263 |
_exit(127);
|
255 |
}
|
264 |
}
|
256 |
|
265 |
|
257 |
int ExecCmd::startExec(const string &cmd, const vector<string>& args,
|
266 |
int ExecCmd::startExec(const string &cmd, const vector<string>& args,
|
|
... |
|
... |
290 |
typedef const char *Ccharp;
|
299 |
typedef const char *Ccharp;
|
291 |
Ccharp *argv;
|
300 |
Ccharp *argv;
|
292 |
argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *));
|
301 |
argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *));
|
293 |
if (argv == 0) {
|
302 |
if (argv == 0) {
|
294 |
LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno));
|
303 |
LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno));
|
295 |
exit(1);
|
304 |
return -1;
|
296 |
}
|
305 |
}
|
297 |
// Fill up argv
|
306 |
// Fill up argv
|
298 |
argv[0] = cmd.c_str();
|
307 |
argv[0] = cmd.c_str();
|
299 |
int i = 1;
|
308 |
int i = 1;
|
300 |
vector<string>::const_iterator it;
|
309 |
vector<string>::const_iterator it;
|
|
... |
|
... |
307 |
int envsize;
|
316 |
int envsize;
|
308 |
for (envsize = 0; ; envsize++)
|
317 |
for (envsize = 0; ; envsize++)
|
309 |
if (environ[envsize] == 0)
|
318 |
if (environ[envsize] == 0)
|
310 |
break;
|
319 |
break;
|
311 |
envv = (Ccharp *)malloc((envsize + m_env.size() + 2) * sizeof(char *));
|
320 |
envv = (Ccharp *)malloc((envsize + m_env.size() + 2) * sizeof(char *));
|
|
|
321 |
if (envv == 0) {
|
|
|
322 |
LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno));
|
|
|
323 |
free(argv);
|
|
|
324 |
return -1;
|
|
|
325 |
}
|
312 |
int eidx;
|
326 |
int eidx;
|
313 |
for (eidx = 0; eidx < envsize; eidx++)
|
327 |
for (eidx = 0; eidx < envsize; eidx++)
|
314 |
envv[eidx] = environ[eidx];
|
328 |
envv[eidx] = environ[eidx];
|
315 |
for (vector<string>::const_iterator it = m_env.begin();
|
329 |
for (vector<string>::const_iterator it = m_env.begin();
|
316 |
it != m_env.end(); it++) {
|
330 |
it != m_env.end(); it++) {
|
317 |
envv[eidx++] = it->c_str();
|
331 |
envv[eidx++] = it->c_str();
|
318 |
}
|
332 |
}
|
319 |
envv[eidx] = 0;
|
333 |
envv[eidx] = 0;
|
320 |
|
334 |
|
321 |
// As we are going to use execve, not execvp, do the PATH
|
335 |
// As we are going to use execve, not execvp, do the PATH thing.
|
322 |
// thing. If the command is not found, exe will be empty and the
|
|
|
323 |
// exec will fail, which is what we want.
|
|
|
324 |
string exe;
|
336 |
string exe;
|
325 |
which(cmd, exe);
|
337 |
if (!which(cmd, exe)) {
|
|
|
338 |
LOGERR(("ExecCmd::startExec: %s not found\n", cmd.c_str()));
|
|
|
339 |
free(argv);
|
|
|
340 |
free(envv);
|
|
|
341 |
return -1;
|
|
|
342 |
}
|
326 |
////////////////////////////////
|
343 |
////////////////////////////////
|
327 |
|
344 |
|
328 |
if (o_useVfork) {
|
345 |
if (o_useVfork) {
|
329 |
m_pid = vfork();
|
346 |
m_pid = vfork();
|
330 |
} else {
|
347 |
} else {
|
|
... |
|
... |
342 |
// dochild does not return. Just in case...
|
359 |
// dochild does not return. Just in case...
|
343 |
_exit(1);
|
360 |
_exit(1);
|
344 |
}
|
361 |
}
|
345 |
|
362 |
|
346 |
// Father process
|
363 |
// Father process
|
|
|
364 |
|
347 |
////////////////////
|
365 |
////////////////////
|
348 |
// Vfork cleanup section
|
366 |
// Vfork cleanup section
|
349 |
free(argv);
|
367 |
free(argv);
|
350 |
free(envv);
|
368 |
free(envv);
|
351 |
///////////////////
|
369 |
///////////////////
|
|
... |
|
... |
353 |
// Set the process group for the child. This is also done in the
|
371 |
// Set the process group for the child. This is also done in the
|
354 |
// child process see wikipedia(Process_group)
|
372 |
// child process see wikipedia(Process_group)
|
355 |
if (setpgid(m_pid, m_pid)) {
|
373 |
if (setpgid(m_pid, m_pid)) {
|
356 |
// This can fail with EACCES if the son has already done execve
|
374 |
// This can fail with EACCES if the son has already done execve
|
357 |
// (linux at least)
|
375 |
// (linux at least)
|
358 |
LOGDEB(("ExecCmd: father setpgid(son)(%d,%d) errno %d (ok)\n",
|
376 |
LOGDEB2(("ExecCmd: father setpgid(son)(%d,%d) errno %d (ok)\n",
|
359 |
m_pid, m_pid, errno));
|
377 |
m_pid, m_pid, errno));
|
360 |
}
|
378 |
}
|
361 |
|
379 |
|
362 |
sigemptyset(&m_blkcld);
|
380 |
sigemptyset(&m_blkcld);
|
363 |
sigaddset(&m_blkcld, SIGCHLD);
|
381 |
sigaddset(&m_blkcld, SIGCHLD);
|
364 |
pthread_sigmask(SIG_BLOCK, &m_blkcld, 0);
|
382 |
pthread_sigmask(SIG_BLOCK, &m_blkcld, 0);
|