Mercurial > notdcc
comparison dcclib/restart.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c7f6b056b673 |
---|---|
1 /* Distributed Checksum Clearinghouse | |
2 * | |
3 * continually restart a daemon | |
4 * | |
5 * Copyright (c) 2008 by Rhyolite Software, LLC | |
6 * | |
7 * This agreement is not applicable to any entity which sells anti-spam | |
8 * solutions to others or provides an anti-spam solution as part of a | |
9 * security solution sold to other entities, or to a private network | |
10 * which employs the DCC or uses data provided by operation of the DCC | |
11 * but does not provide corresponding data to other users. | |
12 * | |
13 * Permission to use, copy, modify, and distribute this software without | |
14 * changes for any purpose with or without fee is hereby granted, provided | |
15 * that the above copyright notice and this permission notice appear in all | |
16 * copies and any distributed versions or copies are either unchanged | |
17 * or not called anything similar to "DCC" or "Distributed Checksum | |
18 * Clearinghouse". | |
19 * | |
20 * Parties not eligible to receive a license under this agreement can | |
21 * obtain a commercial license to use DCC by contacting Rhyolite Software | |
22 * at sales@rhyolite.com. | |
23 * | |
24 * A commercial license would be for Distributed Checksum and Reputation | |
25 * Clearinghouse software. That software includes additional features. This | |
26 * free license for Distributed ChecksumClearinghouse Software does not in any | |
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse | |
28 * software | |
29 * | |
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL | |
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC | |
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES | |
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
37 * SOFTWARE. | |
38 * | |
39 * Rhyolite Software DCC 1.3.103-1.16 $Revision$ | |
40 */ | |
41 | |
42 #include <sys/types.h> | |
43 #include <sys/wait.h> | |
44 #include <signal.h> | |
45 #include <pwd.h> | |
46 #include "dcc_clnt.h" | |
47 | |
48 | |
49 static pid_t start_pid = -1; | |
50 | |
51 static void | |
52 restart_sigterm(int sig) | |
53 { | |
54 if (start_pid > 0 | |
55 && 0 <= kill(start_pid, sig)) | |
56 return; | |
57 exit(-1); | |
58 } | |
59 | |
60 | |
61 | |
62 #define MIN_RESTART_DELAY 5 | |
63 #define MAX_RESTART_DELAY (5*60) | |
64 | |
65 /* stay alive despite core dumps | |
66 * Restart immediately, but not more often than every MINRESTART_DELAY | |
67 * seconds. If the restarts are happening at the maximum rate, | |
68 * halve the rate. */ | |
69 void | |
70 dcc_daemon_restart(const char *rundir, void(reconn)(void)) | |
71 { | |
72 #if defined(WIFEXITED) && defined(WTERMSIG) && defined(WIFSIGNALED) | |
73 pid_t pid; | |
74 time_t next_restart, restart_delay; | |
75 int status; | |
76 const char *etype; | |
77 DCC_PATH pidpath; | |
78 | |
79 signal(SIGHUP, restart_sigterm); | |
80 signal(SIGTERM, restart_sigterm); | |
81 signal(SIGINT, restart_sigterm); | |
82 | |
83 restart_delay = MIN_RESTART_DELAY; | |
84 next_restart = 0; | |
85 for (;;) { | |
86 start_pid = fork(); | |
87 if (!start_pid) { | |
88 #ifdef HAVE_SETPGID | |
89 if (0 > setpgid(0, 0)) | |
90 dcc_error_msg("setpgid(): %s", ERROR_STR()); | |
91 #endif | |
92 /* reconnect sockets or whatever except first time */ | |
93 if (next_restart != 0 | |
94 && reconn) | |
95 reconn(); | |
96 return; | |
97 } | |
98 | |
99 if (start_pid < 0) | |
100 dcc_logbad(EX_OSERR, "(re)start fork(): %s", | |
101 ERROR_STR()); | |
102 | |
103 next_restart = time(0)+restart_delay; | |
104 pid = waitpid(start_pid, &status, 0); | |
105 if (pid < 0) { | |
106 if (errno != EINTR) | |
107 dcc_logbad(EX_OSERR, "restart waitpid(): %s", | |
108 ERROR_STR()); | |
109 exit(0); | |
110 } | |
111 | |
112 start_pid = -1; | |
113 if (WIFEXITED(status)) { | |
114 status = WEXITSTATUS(status); | |
115 etype = "exit "; | |
116 if (status != EX_DCC_RESTART) { | |
117 if (dcc_clnt_debug) | |
118 dcc_error_msg("do not restart after" | |
119 " exit(%d)", | |
120 status); | |
121 exit(status); | |
122 } | |
123 | |
124 } else if (WIFSIGNALED(status)) { | |
125 status = WTERMSIG(status); | |
126 etype = "signal #"; | |
127 if (status != SIGILL | |
128 && status != SIGSEGV | |
129 #ifdef SIGBUS | |
130 && status != SIGBUS | |
131 #endif | |
132 #ifdef SIGXCPU | |
133 && status != SIGXCPU | |
134 #endif | |
135 #ifdef SIGFPE | |
136 && status != SIGFPE | |
137 #endif | |
138 #ifdef SIGSYS | |
139 && status != SIGSYS | |
140 #endif | |
141 #ifdef SIGTRAP | |
142 && status != SIGTRAP | |
143 #endif | |
144 && status != SIGQUIT | |
145 && status != SIGABRT) { | |
146 if (dcc_clnt_debug) | |
147 dcc_error_msg("do not restart after" | |
148 " signal %d", | |
149 status); | |
150 exit(0); | |
151 } | |
152 | |
153 } else { | |
154 dcc_logbad(EX_OSERR, "unknown exit status %#x", status); | |
155 } | |
156 | |
157 next_restart -= time(0); | |
158 if (next_restart > 0 && next_restart <= MAX_RESTART_DELAY) { | |
159 restart_delay *= 2; | |
160 if (restart_delay > MAX_RESTART_DELAY) | |
161 restart_delay = MAX_RESTART_DELAY; | |
162 | |
163 /* while we wait, become the designated target */ | |
164 dcc_error_msg("delay %d seconds to restart after %s%d", | |
165 (int)next_restart, etype, status); | |
166 dcc_pidfile(pidpath, rundir); | |
167 sleep(next_restart); | |
168 unlink(pidpath); | |
169 | |
170 } else { | |
171 restart_delay -= next_restart-1; | |
172 if (restart_delay < MIN_RESTART_DELAY) | |
173 restart_delay = MIN_RESTART_DELAY; | |
174 } | |
175 dcc_error_msg("restart after %s%d", etype, status); | |
176 } | |
177 #endif /* not POSIX */ | |
178 } | |
179 | |
180 | |
181 | |
182 /* change to the UID and GID of a daemon */ | |
183 void | |
184 dcc_daemon_su(const char *user) | |
185 { | |
186 struct passwd *pw; | |
187 | |
188 pw = getpwnam(user); | |
189 if (!pw) { | |
190 dcc_error_msg("getpwnam(%s): %s", user, ERROR_STR()); | |
191 return; | |
192 } | |
193 | |
194 if (0 > setgid(pw->pw_gid)) | |
195 dcc_error_msg("setgid(%d %s): %s", | |
196 (int)pw->pw_gid, user, ERROR_STR()); | |
197 if (0 > setuid(pw->pw_uid)) | |
198 dcc_error_msg("setuid(%d %s): %s", | |
199 (int)pw->pw_uid, user, ERROR_STR()); | |
200 } | |
201 | |
202 | |
203 | |
204 void | |
205 dcc_pidfile(DCC_PATH pidpath, const char *rundir) | |
206 { | |
207 FILE *f; | |
208 | |
209 snprintf(pidpath, sizeof(DCC_PATH), "%s/%s.pid", | |
210 rundir, dcc_progname); | |
211 unlink(pidpath); | |
212 f = fopen(pidpath, "w"); | |
213 if (!f) { | |
214 dcc_error_msg("fopen(%s): %s", pidpath, ERROR_STR()); | |
215 } else { | |
216 #ifdef linux | |
217 /* Linux threads are broken. Signals given the | |
218 * original process are delivered to only the | |
219 * thread that happens to have that PID. The | |
220 * sendmail libmilter thread that needs to hear | |
221 * SIGINT and other signals is known only to the milter. | |
222 * Unless you put its PID into the file, it will not hear | |
223 * the signals. That breaks scripts that need to stop dccm. | |
224 * However, signaling the process group works. */ | |
225 fprintf(f, "-%d\n", (u_int)getpgrp()); | |
226 #else | |
227 fprintf(f, "%d\n", (u_int)getpid()); | |
228 #endif | |
229 fclose(f); | |
230 } | |
231 } |