1 /* process.c -- child process routines for vlock,
2 * the VT locking program for linux
4 * This program is copyright (C) 2007 Frank Benkstein, and is free
5 * software which is freely distributable under the terms of the
6 * GNU General Public License version 2, included as the file COPYING in this
7 * distribution. It is NOT public domain software, and any
8 * redistribution not permitted by the GNU General Public License is
9 * expressly forbidden without prior written permission from
18 #include <sys/resource.h>
25 static void ignore_sigalarm(int __attribute__((unused
)) signum
)
29 bool wait_for_death(pid_t pid
, long sec
, long usec
)
33 struct sigaction oldact
;
34 struct itimerval timer
;
35 struct itimerval otimer
;
38 /* Ignore SIGALRM. The handler must be a real function instead of SIG_IGN
39 * otherwise waitpid() would not get interrupted.
41 * There is a small window here where a previously set alarm might be
43 sigemptyset(&act
.sa_mask
);
44 act
.sa_handler
= ignore_sigalarm
;
46 sigaction(SIGALRM
, &act
, &oldact
);
48 /* Initialize the timer. */
49 timer
.it_value
.tv_sec
= sec
;
50 timer
.it_value
.tv_usec
= usec
;
52 timer
.it_interval
.tv_sec
= 0;
53 timer
.it_interval
.tv_usec
= 0;
56 setitimer(ITIMER_REAL
, &timer
, &otimer
);
58 /* Wait until the child exits or the timer fires. */
59 result
= (waitpid(pid
, &status
, 0) == pid
);
61 /* Possible race condition. If an alarm was set before it may get ignored.
62 * This is probably better than getting killed by our own alarm. */
64 /* Restore the timer. */
65 setitimer(ITIMER_REAL
, &otimer
, NULL
);
67 /* Restore signal handler for SIGALRM. */
68 sigaction(SIGALRM
, &oldact
, NULL
);
73 /* Try hard to kill the given child process. */
74 void ensure_death(pid_t pid
)
78 switch (waitpid(pid
, &status
, WNOHANG
)) {
83 /* Not dead yet. Continue. */
86 /* Already dead. Nothing to do. */
91 (void) kill(pid
, SIGTERM
);
93 /* SIGTERM handler (if any) has 500ms to finish. */
94 if (wait_for_death(pid
, 0, 500000L))
98 (void) kill(pid
, SIGKILL
);
99 /* Child may be stopped. Send SIGCONT just to be sure. */
100 (void) kill(pid
, SIGCONT
);
102 /* Wait until dead. Shouldn't take long. */
103 (void) waitpid(pid
, &status
, 0);
106 /* Close all possibly open file descriptors except STDIN_FILENO, STDOUT_FILENO
107 * and STDERR_FILENO. */
108 void close_all_fds(void)
113 /* Get the maximum number of file descriptors. */
114 if (getrlimit(RLIMIT_NOFILE
, &r
) == 0)
117 /* Hopefully safe default. */
120 /* Close all possibly open file descriptors except STDIN_FILENO,
121 * STDOUT_FILENO and STDERR_FILENO. */
122 for (int i
= 0; i
< maxfd
; i
++) {
135 static int open_devnull(void)
137 static int devnull_fd
= -1;
140 devnull_fd
= open("/dev/null", O_RDWR
);
145 bool create_child(struct child_process
*child
)
151 if (child
->stdin_fd
== REDIRECT_PIPE
) {
152 if (pipe(stdin_pipe
) < 0)
156 if (child
->stdout_fd
== REDIRECT_PIPE
) {
157 if (pipe(stdout_pipe
) < 0)
158 goto stdout_pipe_failed
;
161 if (child
->stderr_fd
== REDIRECT_PIPE
) {
162 if (pipe(stderr_pipe
) < 0)
163 goto stderr_pipe_failed
;
168 if (child
->pid
== 0) {
170 if (child
->stdin_fd
== REDIRECT_PIPE
)
171 (void) dup2(STDIN_FILENO
, stdin_pipe
[0]);
172 else if (child
->stdin_fd
== REDIRECT_DEV_NULL
)
173 (void) dup2(STDIN_FILENO
, open_devnull());
174 else if (child
->stdin_fd
!= NO_REDIRECT
)
175 (void) dup2(STDIN_FILENO
, child
->stdin_fd
);
177 if (child
->stdout_fd
== REDIRECT_PIPE
)
178 (void) dup2(STDIN_FILENO
, stdout_pipe
[1]);
179 else if (child
->stdout_fd
== REDIRECT_DEV_NULL
)
180 (void) dup2(STDIN_FILENO
, open_devnull());
181 else if (child
->stdout_fd
!= NO_REDIRECT
)
182 (void) dup2(STDIN_FILENO
, child
->stdout_fd
);
184 if (child
->stderr_fd
== REDIRECT_PIPE
)
185 (void) dup2(STDIN_FILENO
, stderr_pipe
[1]);
186 else if (child
->stderr_fd
== REDIRECT_DEV_NULL
)
187 (void) dup2(STDIN_FILENO
, open_devnull());
188 else if (child
->stderr_fd
!= NO_REDIRECT
)
189 (void) dup2(STDIN_FILENO
, child
->stderr_fd
);
191 (void) close_all_fds();
193 (void) setgid(getgid());
194 (void) setuid(getuid());
196 if (child
->function
!= NULL
) {
197 _exit(child
->function(child
->argument
));
199 execv(child
->path
, (char *const*)child
->argv
);
208 if (child
->stdin_fd
== REDIRECT_PIPE
) {
210 child
->stdin_fd
= stdin_pipe
[1];
212 (void) close(stdin_pipe
[0]);
215 if (child
->stdout_fd
== REDIRECT_PIPE
) {
217 child
->stdout_fd
= stdout_pipe
[0];
219 (void) close(stdout_pipe
[1]);
222 if (child
->stderr_fd
== REDIRECT_PIPE
) {
224 child
->stderr_fd
= stderr_pipe
[0];
226 (void) close(stderr_pipe
[1]);
232 if (child
->stderr_fd
== REDIRECT_PIPE
) {
233 (void) close(stderr_pipe
[0]);
234 (void) close(stderr_pipe
[1]);
238 if (child
->stdout_fd
== REDIRECT_PIPE
) {
239 (void) close(stdout_pipe
[0]);
240 (void) close(stdout_pipe
[1]);
244 if (child
->stdin_fd
== REDIRECT_PIPE
) {
245 (void) close(stdin_pipe
[0]);
246 (void) close(stdin_pipe
[1]);