lib: Allow reception of mtstdopen info structure.
[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) {
3d6044ab
FT
69 if(WCOREDUMP(st))
70 fprintf(stderr, "multifscgi: child %i (%s) dumped core\n", ch, chspec[0]);
61a9ff68
FT
71 for(i = 0; i < nchildren; i++) {
72 if(children[i] == ch)
73 children[i] = 0;
74 }
75 }
76 chdone = 0;
77 }
78 }
79 sigprocmask(SIG_SETMASK, &ns, NULL);
80}
81
82static void killall(void)
83{
84 int i, try, left, st;
85 sigset_t ss, ns;
86 struct timespec to;
87 pid_t ch;
88 time_t b;
89
90 signal(SIGINT, SIG_DFL);
91 signal(SIGTERM, SIG_DFL);
92 sigemptyset(&ss);
93 sigaddset(&ss, SIGCHLD);
94 sigprocmask(SIG_BLOCK, &ss, &ns);
95 for(try = 0; try < 2; try++) {
96 for(i = 0; i < nchildren; i++) {
97 if(children[i] != 0)
98 kill(children[i], SIGTERM);
99 }
100 b = time(NULL);
101 while(time(NULL) - b < 5) {
102 for(i = 0, left = 0; i < nchildren; i++) {
103 if(children[i] != 0)
104 left++;
105 }
106 if(!left)
107 return;
108 to.tv_sec = 1;
109 to.tv_nsec = 0;
110 pselect(0, NULL, NULL, NULL, &to, &ns);
111 if(chdone) {
112 while((ch = waitpid(-1, &st, WNOHANG)) > 0) {
3d6044ab
FT
113 if(WCOREDUMP(st))
114 fprintf(stderr, "multifscgi: child %i (%s) dumped core\n", ch, chspec[0]);
61a9ff68
FT
115 for(i = 0; i < nchildren; i++) {
116 if(children[i] == ch)
117 children[i] = 0;
118 }
119 }
120 chdone = 0;
121 }
122 }
123 }
124 for(i = 0; i < nchildren; i++) {
125 if(children[i] != 0)
126 kill(children[i], SIGKILL);
127 }
128}
129
130static void chld(int sig)
131{
132 chdone = 1;
133}
134
135static void term(int sig)
136{
137 done = 1;
138}
139
140static void usage(FILE *out)
141{
d6d6fe8e 142 fprintf(out, "usage: multifscgi [-h] NUM PROGRAM [ARGS...]\n");
61a9ff68
FT
143}
144
145int main(int argc, char **argv)
146{
147 int c;
148
121587a5 149 while((c = getopt(argc, argv, "+h")) >= 0) {
61a9ff68
FT
150 switch(c) {
151 case 'h':
152 usage(stdout);
153 return(0);
154 default:
155 usage(stderr);
156 return(1);
157 }
158 }
159 if(argc - optind < 2) {
160 usage(stderr);
161 return(1);
162 }
163 nchildren = atoi(argv[optind]);
164 if(nchildren < 1) {
165 usage(stderr);
166 return(1);
167 }
168 children = szmalloc(sizeof(pid_t) * nchildren);
169 chspec = argv + optind + 1;
170 signal(SIGINT, term);
171 signal(SIGTERM, term);
172 signal(SIGCHLD, chld);
173 manage();
174 killall();
175 return(0);
176}