1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <signal.h>
5 #include "sig.h"
6 #include "direntry.h"
7 #include "strerr.h"
8 #include "error.h"
9 #include "open.h"
10 #include "wait.h"
11 #include "closeonexec.h"
12 #include "fd.h"
13 #include "env.h"
14 #include "str.h"
15 #include "byte.h"
16 #include "pathexec.h"
17
18 #define SERVICES 1000
19
20 #define INFO "svscan: info: "
21 #define WARNING "svscan: warning: "
22 #define FATAL "svscan: fatal: "
23
24 struct {
25 unsigned long dev;
26 unsigned long ino;
27 int flagactive;
28 int flaglog;
29 int pid; /* 0 if not running */
30 int pidlog; /* 0 if not running */
31 int pi[2]; /* defined if flaglog */
32 } x[SERVICES];
33 int numx = 0;
34 int logx = -1;
35 int logpipe[2];
36 const char *logdir = 0;
37 int all_stopped, exit_asap=0;
38
39 char fnlog[260];
40
catch_sig(int sig)41 void catch_sig(int sig)
42 {
43 exit_asap = 1;
44 }
45
start(const char * fn)46 void start(const char *fn)
47 {
48 unsigned int fnlen;
49 struct stat st;
50 int child;
51 int i;
52 const char *args[3];
53 int islog;
54
55 islog = logdir && !str_diff(fn,logdir);
56 if (fn[0] == '.' && !islog) return;
57
58 if (stat(fn,&st) == -1) {
59 strerr_warn4sys(WARNING,"unable to stat ",fn,"");
60 return;
61 }
62
63 if ((st.st_mode & S_IFMT) != S_IFDIR) return;
64
65 for (i = 0;i < numx;++i)
66 if (x[i].ino == st.st_ino)
67 if (x[i].dev == st.st_dev)
68 break;
69
70 if (i == numx) {
71 if (numx >= SERVICES) {
72 strerr_warn4(WARNING,"unable to start ",fn,": running too many services",0);
73 return;
74 }
75 x[i].ino = st.st_ino;
76 x[i].dev = st.st_dev;
77 x[i].pid = 0;
78 x[i].pidlog = 0;
79 x[i].flaglog = 0;
80
81 fnlen = str_len(fn);
82 if (fnlen <= 255) {
83 byte_copy(fnlog,fnlen,fn);
84 byte_copy(fnlog + fnlen,5,"/log");
85 if (stat(fnlog,&st) == 0)
86 x[i].flaglog = S_ISDIR(st.st_mode);
87 else
88 if (errno != error_noent) {
89 strerr_warn4sys(WARNING,"unable to stat ",fn,"/log");
90 return;
91 }
92 }
93
94 if (x[i].flaglog) {
95 if (pipe(x[i].pi) == -1) {
96 strerr_warn4sys(WARNING,"unable to create pipe for ",fn,"");
97 return;
98 }
99 closeonexec(x[i].pi[0]);
100 closeonexec(x[i].pi[1]);
101 }
102 ++numx;
103 }
104
105 x[i].flagactive = 1;
106
107 if (!x[i].pid && !exit_asap)
108 switch(child = fork()) {
109 case -1:
110 strerr_warn4sys(WARNING,"unable to fork for ",fn,"");
111 return;
112 case 0:
113 if (x[i].flaglog)
114 if (fd_move(1,x[i].pi[1]) == -1)
115 strerr_die3sys(111,WARNING,"unable to set up descriptors for ",fn);
116 if (i == logx)
117 if (fd_move(0,logpipe[0]) == -1)
118 strerr_die3sys(111,WARNING,"unable to set up descriptors for ",fn);
119 args[0] = "supervise";
120 args[1] = fn;
121 args[2] = 0;
122 pathexec_run(*args,args,(const char*const*)environ);
123 strerr_die3sys(111,WARNING,"unable to start supervise ",fn);
124 default:
125 x[i].pid = child;
126 all_stopped = 0;
127 }
128 else
129 if (x[i].pid) {
130 all_stopped = 0;
131 if (exit_asap)
132 kill(x[i].pid,SIGTERM);
133 }
134
135 if (x[i].flaglog && !x[i].pidlog && !exit_asap)
136 switch(child = fork()) {
137 case -1:
138 strerr_warn4sys(WARNING,"unable to fork for ",fn,"/log");
139 return;
140 case 0:
141 if (fd_move(0,x[i].pi[0]) == -1)
142 strerr_die4sys(111,WARNING,"unable to set up descriptors for ",fn,"/log");
143 if (chdir(fn) == -1)
144 strerr_die3sys(111,WARNING,"unable to switch to ",fn);
145 args[0] = "supervise";
146 args[1] = "log";
147 args[2] = 0;
148 pathexec_run(*args,args,(const char*const*)environ);
149 strerr_die4sys(111,WARNING,"unable to start supervise ",fn,"/log");
150 default:
151 x[i].pidlog = child;
152 all_stopped = 0;
153 }
154 else
155 if (x[i].flaglog && x[i].pidlog) {
156 all_stopped = 0;
157 if (exit_asap && !x[i].pid)
158 kill(x[i].pidlog,SIGTERM);
159 }
160 }
161
direrror(void)162 void direrror(void)
163 {
164 strerr_warn2sys(WARNING,"unable to read directory");
165 }
166
doit(void)167 void doit(void)
168 {
169 DIR *dir;
170 direntry *d;
171 int i;
172 int r;
173 int wstat;
174
175 for (;;) {
176 r = wait_nohang(&wstat);
177 if (!r) break;
178 if (r == -1) {
179 if (errno == error_intr) continue; /* impossible */
180 break;
181 }
182
183 for (i = 0;i < numx;++i) {
184 if (x[i].pid == r) { x[i].pid = 0; break; }
185 if (x[i].pidlog == r) { x[i].pidlog = 0; break; }
186 }
187 }
188
189 for (i = 0;i < numx;++i)
190 x[i].flagactive = 0;
191
192 dir = opendir(".");
193 if (!dir) {
194 direrror();
195 return;
196 }
197 for (;;) {
198 errno = 0;
199 d = readdir(dir);
200 if (!d) break;
201 start(d->d_name);
202 }
203 if (errno) {
204 direrror();
205 closedir(dir);
206 return;
207 }
208 closedir(dir);
209
210 i = 0;
211 while (i < numx) {
212 if (!x[i].flagactive && !x[i].pid && !x[i].pidlog) {
213 if (x[i].flaglog) {
214 close(x[i].pi[0]);
215 close(x[i].pi[1]);
216 x[i].flaglog = 0;
217 }
218 x[i] = x[--numx];
219 continue;
220 }
221 ++i;
222 }
223 }
224
start_log(void)225 static void start_log(void)
226 {
227 struct stat st;
228
229 /* Make sure the standard file descriptors are open before creating any pipes. */
230 if (fstat(0,&st) != 0 && errno == EBADF)
231 (void) open_read("/dev/null");
232 if (fstat(1,&st) != 0 && errno == EBADF)
233 (void) open_write("/dev/null");
234 if (fstat(2,&st) != 0 && errno == EBADF)
235 (void) open_write("/dev/null");
236
237 if (logdir && stat(logdir,&st) == 0 && S_ISDIR(st.st_mode)) {
238 logx = numx;
239 if (pipe(logpipe) == -1)
240 strerr_die3sys(111,FATAL,"unable to create pipe for ",logdir);
241 closeonexec(logpipe[0]);
242 closeonexec(logpipe[1]);
243 start(logdir);
244 if (numx > logx && x[logx].pid != 0) {
245 (void) fd_copy(1,logpipe[1]);
246 (void) fd_move(2,logpipe[1]);
247 strerr_warn2(INFO,"starting",0);
248 }
249 }
250 }
251
main(int argc,char ** argv)252 int main(int argc,char **argv)
253 {
254 if (argc >= 2)
255 if (chdir(argv[1]) == -1)
256 strerr_die3sys(111,FATAL,"unable to chdir to ",argv[1]);
257 if (argc >= 3)
258 logdir = argv[2];
259
260 start_log();
261 sig_catch(SIGTERM,catch_sig);
262
263 for (;;) {
264 all_stopped = 1;
265 doit();
266 if (all_stopped) break;
267 sleep(exit_asap ? 1 : 5);
268 }
269 return 0;
270 }
271