2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #import <Foundation/Foundation.h>
24 #include <NGObjWeb/NGObjWeb.h>
26 #if defined(__CYGWIN32__) || defined(__MINGW32__)
28 int WOWatchDogApplicationMain
29 (NSString *appName, int argc, const char *argv[])
31 /* no watchdog support on Win* */
32 return WOApplicationMain(appName, argc, argv);
41 #include <sys/types.h>
42 #include <sys/unistd.h>
45 static pid_t child = -1;
46 static NSString *pidFile = nil;
47 static time_t lastFailExit = 0;
48 static unsigned failExitCount = 0;
49 static BOOL killedChild = NO;
51 static void killChild(void) {
55 fprintf(stderr, "watchdog[%i]: terminating child %i ..\n", getpid(), child);
57 if (kill(child, SIGTERM) == 0) {
58 waitpid(child, &status, 0);
61 fprintf(stderr, " terminated child %i", child);
63 if (WIFEXITED(status))
64 fprintf(stderr, " exit=%i", WEXITSTATUS(status));
65 if (WIFSIGNALED(status))
66 fprintf(stderr, " signal=%i", WTERMSIG(status));
68 fprintf(stderr, ".\n");
74 else if (kill(child, SIGKILL)) {
75 waitpid(child, &status, 0);
78 fprintf(stderr, " killed child %i", child);
80 if (WIFEXITED(status))
81 fprintf(stderr, " exit=%i", WEXITSTATUS(status));
82 if (WIFSIGNALED(status))
83 fprintf(stderr, " signal=%i", WTERMSIG(status));
85 fprintf(stderr, ".\n");
94 static void _writePid(NSString *pidFile) {
95 if ([pidFile length] > 0) {
98 if ((pf = fopen([pidFile cString], "w"))) {
99 fprintf(pf, "%i\n", getpid());
105 static void _delPid(void) {
106 if ([pidFile length] > 0) {
107 if (unlink([pidFile cString]) == 0)
112 static void exitWatchdog(void) {
117 static void wsignalHandler(int _signal) {
121 fprintf(stderr, "[%i]: watchdog handling signal ctrl-c ..\n", getpid());
124 /* shouldn't get here */
130 "[%i]: watchdog handling segmentation fault "
131 "(SERIOUS PROBLEM) ..\n",
135 /* shouldn't get here */
139 /* TERM signal (kill 'pid') */
140 fprintf(stderr, "[%i]: watchdog handling SIGTERM ..\n", getpid());
143 /* shouldn't get here */
147 /* HUP signal (restart children) */
148 fprintf(stderr, "[%i]: watchdog handling SIGHUP ..\n", getpid());
151 signal(_signal, wsignalHandler);
158 fprintf(stderr, "[%i]: watchdog handling signal %i ..\n",
181 // NSLog(@"SIGNAL: SIGCHLD");
182 // fetch return state
185 result = waitpid(-1, &returnStatus, WNOHANG);
187 fprintf(stderr, "[%i]: process %i exited with code %i",
188 getpid(), (int)result, WEXITSTATUS(returnStatus));
190 if (WIFSIGNALED(returnStatus)) {
191 fprintf(stderr, " (terminated due to signal %i%s)",
192 WTERMSIG(returnStatus),
193 WCOREDUMP(returnStatus) ? ", coredump" : "");
195 if (WIFSTOPPED(returnStatus)) {
196 fprintf(stderr, " (stopped due to signal %i)",
197 WSTOPSIG(returnStatus));
200 fprintf(stderr, "\n");
210 fprintf(stderr, "watchdog[%i]: caught signal %i\n", getpid(), _signal);
213 signal(_signal, wsignalHandler);
216 static void signalHandler(int _signal) {
217 fprintf(stderr, "[%i]: handling signal %i ..\n",
223 fprintf(stderr, "[%i]: caught signal SIGPIPE\n", getpid());
227 fprintf(stderr, "[%i]: caught signal %i\n", getpid(), _signal);
230 signal(_signal, signalHandler);
233 int WOWatchDogApplicationMain
234 (NSString *appName, int argc, const char *argv[])
236 NSAutoreleasePool *pool;
239 pool = [[NSAutoreleasePool alloc] init];
240 #if LIB_FOUNDATION_LIBRARY || defined(GS_PASS_ARGUMENTS)
242 extern char **environ;
243 [NSProcessInfo initializeWithArguments:(void*)argv count:argc
244 environment:(void*)environ];
248 ud = [NSUserDefaults standardUserDefaults];
250 /* default is to use the watch dog! */
251 /* Note: the Defaults.plist is not yet loaded at this stage! */
252 if ([ud objectForKey:@"WOUseWatchDog"] != nil) {
253 if (![ud boolForKey:@"WOUseWatchDog"])
254 return WOApplicationMain(appName, argc, argv);
264 isVerbose = [[ud objectForKey:@"watchdog_verbose"] boolValue];
265 pidFile = [[[ud objectForKey:@"watchdog_pidfile"] stringValue] copy];
267 /* write current pid to pidfile */
270 /* register exit handler */
271 atexit(exitWatchdog);
273 /* register signal handlers of watch dog */
274 signal(SIGPIPE, wsignalHandler);
275 signal(SIGCHLD, wsignalHandler);
276 signal(SIGINT, wsignalHandler);
277 signal(SIGTERM, wsignalHandler);
278 signal(SIGKILL, wsignalHandler);
279 signal(SIGHUP, wsignalHandler);
284 time_t clientStartTime;
286 clientStartTime = time(NULL);
289 if ((child = fork()) == -1) {
290 fprintf(stderr, "[%i]: fork failed: %s\n", getpid(), strerror(errno));
294 fprintf(stderr, " fork failed %i times, sleeping 60 seconds ..\n",
305 signal(SIGPIPE, SIG_DFL);
306 signal(SIGCHLD, SIG_DFL);
307 signal(SIGINT, SIG_DFL);
308 signal(SIGTERM, SIG_DFL);
309 signal(SIGKILL, SIG_DFL);
312 fprintf(stderr, "starting child %i ..\n", getpid());
314 pidFile = [pidFile stringByAppendingPathExtension:@"child"];
319 exit(WOApplicationMain(appName, argc, argv));
321 /* shouldn't even get here ! */
322 fprintf(stderr, "internal server error !\n");
326 /* parent (watch dog) */
329 time_t clientStopTime;
335 fprintf(stderr, "forked child process %i (#%i) ..\n",
342 if ((result = waitpid(child, &status, 0)) == -1) {
349 "### waiting for child %i (#%i) failed: %s\n",
350 child, forkCount, strerror(errno));
354 clientStopTime = time(NULL);
355 uptime = clientStopTime - clientStartTime;
357 if (WIFSIGNALED(status)) {
359 "### child %i (#%i) was terminated by signal %i "
361 child, forkCount, WTERMSIG(status), uptime);
363 lastFailExit = time(NULL);
366 else if (WIFEXITED(status)) {
369 if ((exitCode = WEXITSTATUS(status)) != 0) {
375 if (failExitCount > 0) {
376 unsigned secsSinceLastFail;
378 secsSinceLastFail = (now - lastFailExit);
380 if (secsSinceLastFail > 120) {
381 /* reset fail count */
384 else if (failExitCount > 20) {
385 printf("### child %i (#%i) already failed %i times "
386 "in the last %i seconds, stopping watchdog !\n",
387 child, forkCount, failExitCount, secsSinceLastFail);
396 "### child %i (#%i) exited with status %i "
397 "(#fails=%i, uptime=%ds).\n",
398 child, forkCount, exitCode, failExitCount, uptime);
402 "### child %i (#%i) exited successfully (uptime=%ds).\n",
403 child, forkCount, uptime);
406 if (exitCode == 123) // ???
411 "### abnormal termination of child %i (#%i) status=%i"
412 "(was not signaled nor exited).",
413 child, forkCount, status);