unix/fiss-minit

msvc.c in master
Repositories | Summary | Log | Files | README | COPYING

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}