Merge with vlock-2
[vlock.git] / src / process.c
bloba5f6ac6b88f804a38431d81906e50c223e2d7e00
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
10 * the author.
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <signal.h>
17 #include <sys/wait.h>
18 #include <sys/resource.h>
19 #include <sys/time.h>
21 #include "process.h"
23 /* Do nothing. */
24 static void ignore_sigalarm(int __attribute__((unused)) signum)
28 bool wait_for_death(pid_t pid, long sec, long usec)
30 int status;
31 struct sigaction act;
32 struct sigaction oldact;
33 struct itimerval timer;
34 struct itimerval otimer;
35 bool result;
37 /* Ignore SIGALRM. The handler must be a real function instead of SIG_IGN
38 * otherwise waitpid() would not get interrupted.
40 * There is a small window here where a previously set alarm might be
41 * ignored. */
42 sigemptyset(&act.sa_mask);
43 act.sa_handler = ignore_sigalarm;
44 act.sa_flags = 0;
45 sigaction(SIGALRM, &act, &oldact);
47 /* Initialize the timer. */
48 timer.it_value.tv_sec = sec;
49 timer.it_value.tv_usec = usec;
50 /* No repetition. */
51 timer.it_interval.tv_sec = 0;
52 timer.it_interval.tv_usec = 0;
54 /* Set the timer. */
55 setitimer(ITIMER_REAL, &timer, &otimer);
57 /* Wait until the child exits or the timer fires. */
58 result = (waitpid(pid, &status, 0) == pid);
60 /* Possible race condition. If an alarm was set before it may get ignored.
61 * This is probably better than getting killed by our own alarm. */
63 /* Restore the timer. */
64 setitimer(ITIMER_REAL, &otimer, NULL);
66 /* Restore signal handler for SIGALRM. */
67 sigaction(SIGALRM, &oldact, NULL);
69 return result;
72 /* Try hard to kill the given child process. */
73 void ensure_death(pid_t pid)
75 int status;
77 switch (waitpid(pid, &status, WNOHANG)) {
78 case -1:
79 /* Not your child? */
80 return;
81 case 0:
82 /* Not dead yet. Continue. */
83 break;
84 default:
85 /* Already dead. Nothing to do. */
86 return;
89 /* Send SIGTERM. */
90 (void) kill(pid, SIGTERM);
92 /* SIGTERM handler (if any) has 500ms to finish. */
93 if (wait_for_death(pid, 0, 500000L))
94 return;
96 // Send SIGKILL. */
97 (void) kill(pid, SIGKILL);
98 /* Child may be stopped. Send SIGCONT just to be sure. */
99 (void) kill(pid, SIGCONT);
101 /* Wait until dead. Shouldn't take long. */
102 (void) waitpid(pid, &status, 0);
105 /* Close all possibly open file descriptors except STDIN_FILENO, STDOUT_FILENO
106 * and STDERR_FILENO. */
107 void close_all_fds(void)
109 struct rlimit r;
110 int maxfd;
112 /* Get the maximum number of file descriptors. */
113 if (getrlimit(RLIMIT_NOFILE, &r) == 0)
114 maxfd = r.rlim_cur;
115 else
116 /* Hopefully safe default. */
117 maxfd = 1024;
119 /* Close all possibly open file descriptors except STDIN_FILENO,
120 * STDOUT_FILENO and STDERR_FILENO. */
121 for (int i = 0; i < maxfd; i++) {
122 switch (i) {
123 case STDIN_FILENO:
124 case STDOUT_FILENO:
125 case STDERR_FILENO:
126 break;
127 default:
128 (void) close(i);
129 break;
134 void create_child(struct child_process *child)