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 }