1 #ifndef __supervise_h
2 #define __supervise_h
3 
4 #include "config.h"
5 
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 
12 #ifndef HAVE_SYSLOG
supervise(char * x)13 static void inline supervise(char *x)
14 {
15 	fatal("You probably don't want to supervise when you cannot log");
16 }
17 #else
18 static int supervised_pid = -1;
19 static int supervised_quit = 0;
handle_sign(int signo)20 static void handle_sign(int signo)
21 {
22 	if (supervised_pid != -1) {
23 		kill(supervised_pid, signo);
24 		supervised_quit = 1;
25 	}
26 }
supervise(char * x)27 static void inline supervise(char *x)
28 {
29 	int fd, status;
30 	int super_pid;
31 	/* GOOD DAEMON PRACTICES */
32 
33 	/* do first fork */
34 	signal(SIGCHLD, SIG_IGN);
35 	switch (fork()) {
36 	case -1: cfatal("fork: %s");
37 	case 0: break;
38 	default: exit(0);
39 	};
40 
41 	/* be a proper daemon */
42 	fd = open("/dev/null", O_RDWR);
43 	if (fd != 0) { close(0); dup2(fd, 0); }
44 	if (fd != 1) { close(1); dup2(fd, 1); }
45 	if (fd != 2) { close(2); dup2(fd, 2); }
46 	if (fd > 2) { close(fd); }
47 
48 	super_pid = getpid();
49 #ifdef HAVE_SETSID
50 	/* change session ID if possible */
51 	(void) setsid();
52 #endif
53 	/* signore Sigpipe */
54 	signal(SIGPIPE, SIG_IGN);
55 
56 	/* we want child notification */
57 	signal(SIGCHLD, SIG_DFL);
58 
59 	/* setup other signals */
60 	signal(SIGSTOP, handle_sign);
61 	signal(SIGCONT, handle_sign);
62 	signal(SIGTERM, handle_sign);
63 	signal(SIGHUP, handle_sign);
64 	signal(SIGINT, handle_sign);
65 
66 	/* do second fork */
67 restart_from_child_l:
68 	switch ((supervised_pid = fork())) {
69 	case -1: cfatal("fork: %s");
70 	case 0: /* child */ return;
71 	};
72 
73 	/* pid file */
74 	if (x && *x == '/') {
75 		FILE *fp;
76 
77 		fp = fopen(x, "w");
78 		fprintf(fp, "%d\n", super_pid);
79 		fclose(fp);
80 	}
81 
82 wait_some_more_l:
83 #ifdef HAVE_WAITPID
84 	waitpid(supervised_pid, &status, 0);
85 #else
86 #ifdef HAVE_WAIT4
87 	wait4(supervised_pid, &status, 0, NULL);
88 #else
89 	while (wait(&status) != supervised_pid);
90 #endif
91 #endif
92 	if (kill(supervised_pid, 0) == -1) {
93 		sleep(1); /* go to sleep for 1 second */
94 		if ((volatile)supervised_quit)
95 			exit(0);
96 		/* wasn't supposed to be dead yet... */
97 		goto restart_from_child_l;
98 	}
99 	supervised_quit = 0;
100 	goto wait_some_more_l;
101 }
102 #endif
103 
104 #endif
105