msvc.c (8860B) download
1#include "minit.h"
2
3#include <errno.h>
4#include <fcntl.h>
5#include <signal.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/file.h>
10#include <unistd.h>
11
12static int infd, outfd;
13
14static char buf[1500];
15
16#define FMT_ULONG 40
17
18static size_t fmt_ulong(char* dest, unsigned long i) {
19 register unsigned long len, tmp, len2;
20 /* first count the number of bytes needed */
21 for (len = 1, tmp = i; tmp > 9; ++len) tmp /= 10;
22 if (dest)
23 for (tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10)
24 *--dest = (char) ((tmp % 10) + '0');
25 return len;
26}
27
28static void addservice(char* service) {
29 char* x;
30 if (strncmp(service, MINITROOT "/", strlen(service)) == 0)
31 service += sizeof(MINITROOT "/") - 1;
32 x = service + strlen(service) - 1;
33 while (x > service && *x == '/') {
34 *x = 0;
35 --x;
36 }
37 strncpy(buf + 1, service, 1400);
38 buf[1400] = 0;
39}
40
41static int addreadwrite(char* service) {
42 addservice(service);
43 write(infd, buf, strlen(buf));
44 return read(outfd, buf, 1500);
45}
46
47/* return PID, 0 if error */
48static pid_t __readpid(char* service) {
49 int len;
50 buf[0] = 'p';
51 len = addreadwrite(service);
52 if (len < 0) return 0;
53 buf[len] = 0;
54 return atoi(buf);
55}
56
57/* return nonzero if error */
58static int respawn(char* service, int yesno) {
59 int len;
60 buf[0] = yesno ? 'R' : 'r';
61 len = addreadwrite(service);
62 return (len != 1 || buf[0] == '0');
63}
64
65/* return nonzero if error */
66static int setpid(char* service, pid_t pid) {
67 char* tmp;
68 int len;
69 buf[0] = 'P';
70 addservice(service);
71 tmp = buf + strlen(buf) + 1;
72 tmp[fmt_ulong(tmp, pid)] = 0;
73 write(infd, buf, strlen(buf) + strlen(tmp) + 2);
74 len = read(outfd, buf, 1500);
75 return (len != 1 || buf[0] == '0');
76}
77
78/* return nonzero if error */
79static int check_remove(char* service) {
80 int len;
81 buf[0] = 'C';
82 len = addreadwrite(service);
83 return (len != 1 || buf[0] == '0');
84}
85
86/* return nonzero if error */
87static int startservice(char* service) {
88 int len;
89 buf[0] = 's';
90 len = addreadwrite(service);
91 return (len != 1 || buf[0] == '0');
92}
93
94/* return uptime, 0 if error */
95static unsigned long uptime(char* service) {
96 int len;
97 buf[0] = 'u';
98 len = addreadwrite(service);
99 if (len < 0) return 0;
100 buf[len] = 0;
101 return atoi(buf);
102}
103
104static void dumphistory() {
105 char tmp[16384];
106 int i, j;
107 char first, last;
108 first = 1;
109 last = 'x';
110 write(infd, "h", 1);
111 for (;;) {
112 int done;
113 j = read(outfd, tmp, sizeof(tmp));
114 if (j < 1) break;
115 done = i = 0;
116 if (first) {
117 if (tmp[0] == '0') {
118 fprintf(stderr, "minit compiled without history support.");
119 return;
120 }
121 i += 2;
122 } else {
123 if (!tmp[0] && last == '\n') break;
124 }
125 for (; i < j; ++i)
126 if (!tmp[i]) {
127 tmp[i] = done ? 0 : '\n';
128 if (i < j && !tmp[i + 1]) {
129 done = 1;
130 --j;
131 }
132 }
133 if (first)
134 write(1, tmp + 2, j - 2);
135 else
136 write(1, tmp, j);
137 if (done) break;
138 last = tmp[j - 1];
139 first = 0;
140 }
141}
142
143static void dumpdependencies(char* service) {
144 char tmp[16384];
145 int i, j;
146 char first, last;
147 buf[0] = 'd';
148 addservice(service);
149 write(infd, buf, strlen(buf));
150 first = 1;
151 last = 'x';
152 for (;;) {
153 int done;
154 j = read(outfd, tmp, sizeof(tmp));
155 if (j < 1) break;
156 done = i = 0;
157 if (first) {
158 if (tmp[0] == '0') {
159 fprintf(stderr, service, ": no such service.");
160 return;
161 }
162 i += 2;
163 } else {
164 if (!tmp[0] && last == '\n') break;
165 }
166 for (; i < j; ++i)
167 if (!tmp[i]) {
168 tmp[i] = done ? 0 : '\n';
169 if (i < j && !tmp[i + 1]) {
170 done = 1;
171 --j;
172 }
173 }
174 if (first)
175 write(1, tmp + 2, j - 2);
176 else
177 write(1, tmp, j);
178 if (done) break;
179 last = tmp[j - 1];
180 first = 0;
181 }
182}
183
184int main(int argc, char* argv[]) {
185 if (argc < 2) {
186 printf(
187 "usage: msvc -[uodpchaitkogC] service\n"
188 " msvc -Ppid service\n"
189 " -u\tup; start service with respawn\n"
190 " -o\tonce; start service without respawn\n"
191 " -d\tdown; disable respawn, stop service\n"
192 " -p\tpause; send SIGSTOP\n"
193 " -c\tcontinue; send SIGCONT\n"
194 " -h\thangup; send SIGHUP\n"
195 " -a\talarm; send SIGALRM\n"
196 " -i\tintr; send SIGINT\n"
197 " -t\tterminate; send SIGTERM\n"
198 " -k\tkill; send SIGKILL\n"
199 " -g\tget; output just the PID\n"
200 " -Ppid\tset PID of service (for pidfilehack)\n"
201 " -D service\tprint services started as dependency\n"
202 " -H\tprint last n respawned services\n"
203 " -C\tClear; remove service form active list\n");
204 return 0;
205 }
206 infd = open(MINITROOT "/in", O_WRONLY);
207 outfd = open(MINITROOT "/out", O_RDONLY);
208 if (infd >= 0) {
209 while (lockf(infd, F_LOCK, 1)) {
210 fprintf(stderr, "could not acquire lock!");
211 sleep(1);
212 }
213 if (argc == 2 && argv[1][1] != 'H') {
214 pid_t pid = __readpid(argv[1]);
215 if (buf[0] != '0') {
216 unsigned long len;
217 unsigned long ut = uptime(argv[1]);
218
219 if (isatty(1)) {
220 char tmp[FMT_ULONG + 20];
221 char tmp2[FMT_ULONG];
222 char* what;
223
224 if (pid == 0)
225 what = "down ";
226 else if (pid == 1)
227 what = "finished ";
228 else {
229 len = snprintf(tmp, sizeof(tmp), "up (pid %u)", pid);
230 what = tmp;
231 }
232 tmp2[fmt_ulong(tmp2, ut)] = 0;
233 printf("%s: %s%s seconds\n", argv[1], what, tmp2);
234 } else {
235 char tmp[FMT_ULONG * 2 + 5];
236 len = fmt_ulong(tmp, pid);
237 tmp[len] = ' ';
238 ++len;
239 len += fmt_ulong(tmp + len, ut);
240 tmp[len] = '\n';
241 write(1, tmp, len + 1);
242 }
243
244 if (pid == 0)
245 return 2;
246 else if (pid == 1)
247 return 3;
248 else
249 return 0;
250 } else
251 fprintf(stderr, "%s: no such service\n.", argv[1]);
252 return 1;
253 } else {
254 int i;
255 int ret = 0;
256 int sig = 0;
257 pid_t pid;
258 if (argv[1][0] == '-') {
259 switch (argv[1][1]) {
260 case 'g':
261 for (i = 2; i < argc; ++i) {
262 pid = __readpid(argv[i]);
263 if (pid < 2) {
264 fprintf(stderr, "%s: %s\n", argv[i], pid == 1 ? "service terminated" : "no such service");
265 ret = 1;
266 } else {
267 char tmp[FMT_ULONG];
268 int i;
269 tmp[i = fmt_ulong(tmp, pid)] = '\n';
270 write(1, tmp, i + 1);
271 }
272 }
273 break;
274 case 'p':
275 sig = SIGSTOP;
276 goto dokill;
277 break;
278 case 'c':
279 sig = SIGCONT;
280 goto dokill;
281 break;
282 case 'h':
283 sig = SIGHUP;
284 goto dokill;
285 break;
286 case 'a':
287 sig = SIGALRM;
288 goto dokill;
289 break;
290 case 'i':
291 sig = SIGINT;
292 goto dokill;
293 break;
294 case 't':
295 sig = SIGTERM;
296 goto dokill;
297 break;
298 case 'k':
299 sig = SIGKILL;
300 goto dokill;
301 break;
302 case 'o':
303 for (i = 2; i < argc; ++i)
304 if (startservice(argv[i]) || respawn(argv[i], 0)) {
305 fprintf(stderr, "Could not start %s\n", argv[i]);
306 ret = 1;
307 }
308 break;
309 case 'd':
310 for (i = 2; i < argc; ++i) {
311 pid = __readpid(argv[i]);
312 if (pid == 0) {
313 fprintf(stderr, "%s: no such service\n", argv[i]);
314 ret = 1;
315 } else if (pid == 1)
316 continue;
317 else if (respawn(argv[i], 0) || kill(pid, SIGTERM) || kill(pid, SIGCONT))
318 fprintf(stderr, "%s: failed to send signal\n", argv[i]);
319 }
320 break;
321 case 'u':
322 for (i = 2; i < argc; ++i)
323 if (startservice(argv[i]) || respawn(argv[i], 1)) {
324 fprintf(stderr, "Could not start %s\n", argv[i]);
325 ret = 1;
326 }
327 break;
328 case 'C':
329 for (i = 2; i < argc; ++i)
330 if (check_remove(argv[i])) {
331 fprintf(stderr, "%s could not be cleared\n", argv[i]);
332 ret = 1;
333 }
334 break;
335 case 'P':
336 pid = atoi(argv[1] + 2);
337 if (pid > 1)
338 if (setpid(argv[2], pid)) {
339 fprintf(stderr, "Could not set PID of service %s\n", argv[2]);
340 ret = 1;
341 }
342 break;
343 case 'H':
344 dumphistory();
345 break;
346 case 'D':
347 dumpdependencies(argv[2]);
348 break;
349 }
350 }
351 return ret;
352 dokill:
353 for (i = 2; i < argc; i++) {
354 pid = __readpid(argv[i]);
355 if (!pid) {
356 fprintf(stderr, "%s: no such service\n", argv[i]);
357 ret = 1;
358 } else if (pid == 1) {
359 fprintf(stderr, "%s: service not running\n", argv[i]);
360 ret = 1;
361 } else if (kill(pid, sig)) {
362 char tmp[FMT_ULONG];
363 char tmp2[FMT_ULONG];
364 char* s;
365 switch (errno) {
366 case EINVAL:
367 s = "invalid signal";
368 break;
369 case EPERM:
370 s = "permission denied";
371 break;
372 case ESRCH:
373 s = "no such pid";
374 break;
375 default:
376 s = "unknown error";
377 }
378 tmp[fmt_ulong(tmp, sig)] = 0;
379 tmp2[fmt_ulong(tmp2, pid)] = 0;
380 fprintf(stderr, "%s: could not send signal %s to PID %s: %s\n", argv[i], tmp, tmp2, s);
381 ret = 1;
382 }
383 }
384 return ret;
385 }
386 } else {
387 fprintf(stderr, "minit: could not open " MINITROOT "/in or " MINITROOT "/out\n");
388 return 1;
389 }
390}