spawnvp.c
2.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2003, 2005-2007, 2009-2012 Free Software
Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
/* See Advanced Programming in the UNIX Environment, Stevens,
* program 10.20 for the rational for the signal handling. I
* had to look it up, so if somebody else is curious, thats where
* to find it.
*/
int
mu_spawnvp (const char *prog, char *av[], int *stat)
{
pid_t pid;
int err = 0;
int progstat;
struct sigaction ignore;
struct sigaction saveintr;
struct sigaction savequit;
sigset_t chldmask;
sigset_t savemask;
if (!prog || !av)
return EINVAL;
ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */
ignore.sa_flags = 0;
sigemptyset (&ignore.sa_mask);
if (sigaction (SIGINT, &ignore, &saveintr) < 0)
return errno;
if (sigaction (SIGQUIT, &ignore, &savequit) < 0)
{
sigaction (SIGINT, &saveintr, NULL);
return errno;
}
sigemptyset (&chldmask); /* now block SIGCHLD */
sigaddset (&chldmask, SIGCHLD);
if (sigprocmask (SIG_BLOCK, &chldmask, &savemask) < 0)
{
sigaction (SIGINT, &saveintr, NULL);
sigaction (SIGQUIT, &savequit, NULL);
return errno;
}
pid = fork ();
if (pid < 0)
{
err = errno;
}
else if (pid == 0)
{ /* child */
/* restore previous signal actions & reset signal mask */
sigaction (SIGINT, &saveintr, NULL);
sigaction (SIGQUIT, &savequit, NULL);
sigprocmask (SIG_SETMASK, &savemask, NULL);
execvp (prog, av);
_exit (127); /* exec error */
}
else
{ /* parent */
while (waitpid (pid, &progstat, 0) < 0)
if (errno != EINTR)
{
err = errno; /* error other than EINTR from waitpid() */
break;
}
if (err == 0 && stat)
*stat = progstat;
}
/* restore previous signal actions & reset signal mask */
/* preserve first error number, but still try and reset the signals */
if (sigaction (SIGINT, &saveintr, NULL) < 0)
err = err ? err : errno;
if (sigaction (SIGQUIT, &savequit, NULL) < 0)
err = err ? err : errno;
if (sigprocmask (SIG_SETMASK, &savemask, NULL) < 0)
err = err ? err : errno;
return err;
}