Merge branch 'master' of git.dolda2000.com:/srv/git/r/ashd
[ashd.git] / src / multifscgi.c
CommitLineData
61a9ff68
FT
1/*
2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include <signal.h>
24#include <sys/wait.h>
25#include <time.h>
d6d6fe8e 26#include <errno.h>
61a9ff68
FT
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <utils.h>
32
33static int nchildren;
34static pid_t *children;
35static char **chspec;
36static volatile int done, chdone;
37
38static void runchild(void)
39{
40 execvp(chspec[0], chspec);
d6d6fe8e 41 fprintf(stderr, "%s: %s", chspec[0], strerror(errno));
61a9ff68
FT
42 exit(127);
43}
44
45static void manage(void)
46{
47 int i, st;
48 sigset_t ss, ns;
49 pid_t ch;
50
51 sigemptyset(&ss);
52 sigaddset(&ss, SIGCHLD);
53 sigaddset(&ss, SIGTERM);
54 sigaddset(&ss, SIGINT);
55 sigprocmask(SIG_BLOCK, &ss, &ns);
56 while(!done) {
57 for(i = 0; i < nchildren; i++) {
58 if(children[i] == 0) {
59 if((ch = fork()) < 0)
60 break;
61 if(ch == 0)
62 runchild();
63 children[i] = ch;
64 }
65 }
66 pselect(0, NULL, NULL, NULL, NULL, &ns);
67 if(chdone) {
68 while((ch = waitpid(-1, &st, WNOHANG)) > 0) {
69 for(i = 0; i < nchildren; i++) {
70 if(children[i] == ch)
71 children[i] = 0;
72 }
73 }
74 chdone = 0;
75 }
76 }
77 sigprocmask(SIG_SETMASK, &ns, NULL);
78}
79
80static void killall(void)
81{
82 int i, try, left, st;
83 sigset_t ss, ns;
84 struct timespec to;
85 pid_t ch;
86 time_t b;
87
88 signal(SIGINT, SIG_DFL);
89 signal(SIGTERM, SIG_DFL);
90 sigemptyset(&ss);
91 sigaddset(&ss, SIGCHLD);
92 sigprocmask(SIG_BLOCK, &ss, &ns);
93 for(try = 0; try < 2; try++) {
94 for(i = 0; i < nchildren; i++) {
95 if(children[i] != 0)
96 kill(children[i], SIGTERM);
97 }
98 b = time(NULL);
99 while(time(NULL) - b < 5) {
100 for(i = 0, left = 0; i < nchildren; i++) {
101 if(children[i] != 0)
102 left++;
103 }
104 if(!left)
105 return;
106 to.tv_sec = 1;
107 to.tv_nsec = 0;
108 pselect(0, NULL, NULL, NULL, &to, &ns);
109 if(chdone) {
110 while((ch = waitpid(-1, &st, WNOHANG)) > 0) {
111 for(i = 0; i < nchildren; i++) {
112 if(children[i] == ch)
113 children[i] = 0;
114 }
115 }
116 chdone = 0;
117 }
118 }
119 }
120 for(i = 0; i < nchildren; i++) {
121 if(children[i] != 0)
122 kill(children[i], SIGKILL);
123 }
124}
125
126static void chld(int sig)
127{
128 chdone = 1;
129}
130
131static void term(int sig)
132{
133 done = 1;
134}
135
136static void usage(FILE *out)
137{
d6d6fe8e 138 fprintf(out, "usage: multifscgi [-h] NUM PROGRAM [ARGS...]\n");
61a9ff68
FT
139}
140
141int main(int argc, char **argv)
142{
143 int c;
144
121587a5 145 while((c = getopt(argc, argv, "+h")) >= 0) {
61a9ff68
FT
146 switch(c) {
147 case 'h':
148 usage(stdout);
149 return(0);
150 default:
151 usage(stderr);
152 return(1);
153 }
154 }
155 if(argc - optind < 2) {
156 usage(stderr);
157 return(1);
158 }
159 nchildren = atoi(argv[optind]);
160 if(nchildren < 1) {
161 usage(stderr);
162 return(1);
163 }
164 children = szmalloc(sizeof(pid_t) * nchildren);
165 chspec = argv + optind + 1;
166 signal(SIGINT, term);
167 signal(SIGTERM, term);
168 signal(SIGCHLD, chld);
169 manage();
170 killall();
171 return(0);
172}