Files
bongo/src/apps/manager/manager.c
T

1045 lines
26 KiB
C

#include <config.h>
#include <xpl.h>
#include <bongoutil.h>
#include <msgapi.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#define LOCKFILE XPL_DEFAULT_WORK_DIR "/bongomanager.pid"
#define SLAPD_LOCKFILE XPL_DEFAULT_WORK_DIR "/bongo-slapd.pid"
/* Don't restart agents if they crash n times within m seconds of each other */
#define MAX_CRASHES 3
#define CRASH_WINDOW 10
typedef struct {
const char *program;
const char *dn;
int priority;
BOOL willCallback;
} BongoAgentSpec;
typedef struct {
BongoAgentSpec spec;
/* Agent configuration */
int enabled;
/* Execution state */
pid_t pid;
int exitStatus;
BOOL waitingForCallback;
/* Crashy agent detection */
BOOL crashed;
time_t lastCrash;
int numCrashes;
BOOL crashy;
} BongoAgent;
/* FIXME: these shouldn't be hard-coded */
static const BongoAgentSpec AgentSpecs[] = {
{ "bongodmc", MSGSRV_AGENT_DMC, 0, FALSE },
{ "bongostore", MSGSRV_AGENT_STORE, 2, FALSE },
{ "bongoqueue", MSGSRV_AGENT_QUEUE, 3, FALSE },
{ "bongoantispam", MSGSRV_AGENT_ANTISPAM, 3, FALSE },
{ "bongoavirus", MSGSRV_AGENT_ANTIVIRUS, 3, FALSE },
{ "bongocollector", MSGSRV_AGENT_COLLECTOR, 5, FALSE },
{ "bongomailprox", MSGSRV_AGENT_PROXY, 5, FALSE },
{ "bongoconnmgr", MSGSRV_AGENT_CONNMGR, 2, FALSE },
{ "bongopluspack", PLUSPACK_AGENT, 4, FALSE },
{ "bongorules", MSGSRV_AGENT_RULESRV, 3, FALSE },
{ "bongosmtp", MSGSRV_AGENT_SMTP, 3, FALSE },
{ "bongoimap", MSGSRV_AGENT_IMAP, 3, FALSE },
{ "bongopop3", MSGSRV_AGENT_POP, 3, FALSE },
{ "bongocalcmd", MSGSRV_AGENT_CALCMD, 3, FALSE },
};
static BongoArray *AllAgents;
static pid_t LeaderPID = 0;
static pid_t SlapdPID = 0;
static BOOL Exiting = FALSE;
static BOOL ChildError = FALSE;
static BOOL ReloadNow = FALSE;
static int HighestPriority = 0;
MDBHandle DirectoryHandle = NULL;
char ServerDN[MDB_MAX_OBJECT_CHARS + 1];
static BongoAgent *
FindAgentByPid(pid_t pid)
{
unsigned int i;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
if (agent->pid == pid) {
return agent;
}
}
return NULL;
}
static BongoAgent *
FindAgentByDn(const char *dn)
{
unsigned int i;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
if (!XplStrCaseCmp(agent->spec.dn, dn)) {
return agent;
}
}
return NULL;
}
static BOOL
ProcessAgentList(MDBValueStruct *list,
MDBValueStruct *v)
{
unsigned long i;
BOOL result = TRUE;
for (i = 0; i < list->Used; i++) {
BongoAgent *agent;
char *p;
p = strrchr(list->Value[i], '\\');
if (!p) {
continue;
}
/* FIXME: should check the type of the node and see if it's a
* BongoAgent. For now, special case a node we know isn't a
* BongoAgent */
if (!XplStrCaseCmp(p + 1, "User Settings")) {
continue;
}
agent = FindAgentByDn(p + 1);
if (!agent) {
fprintf(stderr, "bongomanager: Unknown agent '%s'\n", p + 1);
continue;
}
if ((MDBRead(list->Value[i], MSGSRV_A_DISABLED, v) == 0) || (v->Value[0][0] != '1')) {
agent->enabled = TRUE;
MDBFreeValues(v);
}
}
return result;
}
static BOOL
CheckAgentConfiguration(void)
{
MDBValueStruct *list;
MDBValueStruct *config;
BOOL result;
list = MDBCreateValueStruct(DirectoryHandle, NULL);
if (!list) {
fprintf(stderr, "bongomanager: could not create value struct\n");
return FALSE;
}
config = MDBCreateValueStruct(DirectoryHandle, NULL);
if (!config) {
fprintf(stderr, "bongomanager: could not create value struct\n");
MDBDestroyValueStruct(list);
return FALSE;
}
result = MDBEnumerateObjects(ServerDN,
NULL,
NULL,
list);
if (result && list->Used) {
result = ProcessAgentList(list, config);
} else {
result = FALSE;
}
MDBFreeValues(list);
MDBDestroyValueStruct(list);
MDBDestroyValueStruct(config);
return result;
}
static BOOL
GetAgents(void)
{
unsigned int i;
unsigned int numSpecs = sizeof(AgentSpecs) / sizeof(BongoAgentSpec);
AllAgents = BongoArrayNew(sizeof(BongoAgent), numSpecs);
for (i = 0; i < numSpecs; i++) {
BongoAgent agent = {{0,} };
agent.spec = AgentSpecs[i];
agent.enabled = FALSE; /* Will be enabled by CheckAgentConfiguration */
if (agent.spec.priority > HighestPriority) {
HighestPriority = agent.spec.priority;
}
BongoArrayAppendValue(AllAgents, agent);
}
return CheckAgentConfiguration();
}
static int
AgentsStillRunning(void)
{
unsigned int i;
int ret = 0;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
if (agent->pid != 0) {
ret++;
}
}
return ret;
}
static void
BlameAgents(void)
{
unsigned int i;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
if (agent->pid != 0) {
fprintf(stderr, "%s ", agent->spec.program);
}
}
}
static void
Reap(void)
{
BongoAgent *agent;
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
while (pid > 0) {
agent = FindAgentByPid(pid);
if (agent) {
agent->pid = 0;
agent->exitStatus = status;
agent->waitingForCallback = FALSE;
if (!Exiting && WIFSIGNALED(status)) {
fprintf(stderr, "bongomanager: %s terminated with signal %d.\n",
agent->spec.program, WTERMSIG(status));
if (WTERMSIG(status) != SIGTERM) {
agent->crashed = TRUE;
}
} else if (!Exiting) {
fprintf(stderr, "bongomanager: %s exited\n", agent->spec.program);
}
}
pid = waitpid(-1, &status, WNOHANG);
}
}
static BOOL
WaitingForCallbacks(void)
{
unsigned int i;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
if (agent->waitingForCallback) {
return TRUE;
}
}
return FALSE;
}
static BOOL
WaitForCallbacks(void)
{
/* FIXME: this isn't implemented yet */
int i;
for (i = 0; i < 10; i++) {
if (!WaitingForCallbacks()) {
return TRUE;
}
XplDelay(500);
}
return FALSE;
}
static void
StartAgent(BongoAgent *agent)
{
agent->waitingForCallback = agent->spec.willCallback;
fflush(stdout);
/* Give the agent root so it can bind to ports */
XplSetEffectiveUserId(0);
agent->pid = fork();
if (agent->pid == 0) { /* child */
char *args[2];
char path[XPL_MAX_PATH];
int err;
struct rlimit rlim;
rlim.rlim_max = 20480;
rlim.rlim_cur = 20480;
err = setrlimit(RLIMIT_NOFILE, &rlim);
if (err != 0) {
fprintf(stderr, "couldn't set rlimit: %s\n", strerror(errno));
}
if (LeaderPID == 0) {
setpgid(0, 0);
} else {
setpgid(0, LeaderPID);
}
if (agent->spec.program[0] == '/') {
BongoStrNCpy(path, agent->spec.program, XPL_MAX_PATH);
} else {
snprintf(path, XPL_MAX_PATH, "%s/%s", XPL_DEFAULT_BIN_DIR, agent->spec.program);
}
args[0] = path;
args[1] = NULL;
execv(path, args);
fprintf(stderr, "failed to exec %s (%s)\n", args[0], strerror(errno));
exit(1);
} else { /* parent */
if (XplSetEffectiveUser(MsgGetUnprivilegedUser()) < 0) {
fprintf(stderr, "bongomanager: Could not drop to unprivileged user '%s', Exiting.\n",
MsgGetUnprivilegedUser());
exit(1);
}
if (LeaderPID == 0) {
LeaderPID = agent->pid;
}
}
}
static void
ResetCrashiness(void)
{
unsigned int i;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
agent->crashy = FALSE;
agent->lastCrash = 0;
agent->numCrashes = 0;
}
}
static BOOL
CheckCrashyAgent(BongoAgent *agent)
{
if (agent->crashy) {
return TRUE;
}
if (!agent->crashed) {
return FALSE;
}
agent->crashed = FALSE;
time_t crashTime = time(NULL);
if (crashTime - agent->lastCrash > CRASH_WINDOW) {
/* Outside the window, reset the crash timer */
agent->numCrashes = 0;
}
agent->numCrashes++;
agent->lastCrash = crashTime;
if (agent->numCrashes == MAX_CRASHES) {
fprintf(stderr, "bongomanager: %s has crashed %d times within %d seconds of each other, not restarting.\n",
agent->spec.program, MAX_CRASHES, CRASH_WINDOW);
agent->crashy = TRUE;
return TRUE;
}
return FALSE;
}
static BOOL
StartAgentsWithPriority(int priority, BOOL onlyCrashed, BOOL printMessage)
{
unsigned int i;
for (i = 0; i < AllAgents->len; i++) {
BongoAgent *agent = &BongoArrayIndex(AllAgents, BongoAgent, i);
if (agent->enabled
&& agent->spec.priority == priority
&& agent->pid == 0
&& (!onlyCrashed || agent->crashed)
&& !CheckCrashyAgent(agent)) {
if (printMessage) {
printf("bongomanager: starting %s\n", agent->spec.program);
}
StartAgent(agent);
}
}
return WaitForCallbacks();
}
static void
StartAgents(BOOL onlyCrashed, BOOL printMessage)
{
int i;
for (i = 0; i <= HighestPriority; i++) {
StartAgentsWithPriority(i, onlyCrashed, printMessage);
}
}
static void
SignalHandler(int signo)
{
switch(signo) {
case SIGCHLD :
return;
case SIGINT:
case SIGTERM :
if (!Exiting) {
/* Politely request that the children exit */
if (LeaderPID != 0) {
killpg(LeaderPID, signo);
}
Exiting = TRUE;
} else {
/* Second time through, kill the children with prejudice */
if (LeaderPID != 0) {
killpg(LeaderPID, SIGKILL);
}
if (SlapdPID != 0) {
kill(SlapdPID, SIGKILL);
}
XplExit(0);
}
break;
case SIGUSR1 :
ReloadNow = TRUE;
break;
}
}
static int
Lock(BOOL force)
{
char pid[20];
int fd;
int remaining;
int written;
int ret;
int mode;
mode = O_CREAT | O_WRONLY;
if (!force) {
mode |= O_EXCL;
}
fd = open(LOCKFILE, mode, S_IREAD | S_IWRITE);
if (fd == -1) {
return -1;
}
remaining = snprintf(pid, sizeof(pid), "%d\n", getpid());
if (remaining > (int)sizeof(pid)) {
fprintf(stderr, "bongomanager: unlikely pid, Exiting\n");
exit(1);
}
ret = 0;
written = 0;
while (remaining > 0) {
ret = write(fd, pid + written, remaining);
if (ret != -1) {
remaining -= ret;
written += ret;
} else if (errno == EINTR) {
continue;
} else {
return ret;
}
}
if (close(fd) == -1) {
return -1;
}
return ret;
}
static BOOL
Unlock(const char *lockfile)
{
if (unlink(lockfile) == -1) {
fprintf(stderr, "bongomanager: couldn't unlink %s\n", LOCKFILE);
return FALSE;
}
return TRUE;
}
static pid_t
ReadPid(const char *filename)
{
FILE *f;
char pidstr[20];
pid_t ret = -1;
f = fopen(filename, "r");
if (f) {
if (fgets(pidstr, sizeof(pidstr), f)) {
ret = (pid_t)strtol(pidstr, NULL, 10);
}
fclose(f);
} else {
return -1;
}
return ret;
}
static void
WaitOnPidFile(void)
{
struct stat buf;
while (stat(LOCKFILE, &buf) != -1) {
XplDelay(500);
}
}
static void
ShowHelp(void)
{
printf("Usage: bongomanager [OPTIONS]\n"
"Starts and manages Bongo processes.\n\n"
"Normal options:\n"
"\t-d: Run in background after starting agents.\n"
"\t-k: Keep agents alive, restarting them after crashes.\n"
"\t-f: Force start, replacing " LOCKFILE ".\n"
"\t-s: Shut down an already-running bongomanager.\n"
"\t-r: Ask a running bongomanager to restart stopped agents.\n"
"Managed-slapd options:\n"
"\t-l: Only start the slapd server.\n"
"\t-e: Kill existing slapd server.\n"
);
}
static BOOL
ParseArgs(int argc, char **argv,
BOOL *daemonize,
BOOL *force,
BOOL *keepAlive,
BOOL *shutdown,
BOOL *reload,
BOOL *slapdOnly,
BOOL *killExistingSlapd)
{
int arg;
*daemonize = *force = *keepAlive = *shutdown = *reload = *slapdOnly = *killExistingSlapd = FALSE;
while ((arg = getopt(argc, argv, "dfksrhle")) != -1) {
switch(arg) {
case 'd':
*daemonize = TRUE;
break;
case 'f' :
*force = TRUE;
break;
case 'k' :
*keepAlive = TRUE;
break;
case 's' :
*shutdown = TRUE;
break;
case 'r' :
*reload = TRUE;
break;
case 'l' :
*slapdOnly = TRUE;
break;
case 'e' :
*killExistingSlapd = TRUE;
break;
case 'h' :
case '?' :
return FALSE;
}
}
if (*shutdown && (*daemonize || *force || *reload || *keepAlive || *slapdOnly || *killExistingSlapd)) {
fprintf(stderr, "%s: -s cannot be supplied with other options.\n", argv[0]);
return FALSE;
}
if (*reload && (*daemonize || *force || *keepAlive || *slapdOnly || *killExistingSlapd)) {
fprintf(stderr, "%s: -r cannot be supplied with other options.\n", argv[0]);
return FALSE;
}
if (*slapdOnly && (*keepAlive)) {
fprintf(stderr, "%s: -l cannot be supplied with other options.\n", argv[0]);
return FALSE;
}
return TRUE;
}
static int
StartSlapd(BOOL killExisting)
{
int status = 0;
int err;
char buf[MDB_MAX_OBJECT_CHARS + 1];
char url[MDB_MAX_OBJECT_CHARS + 1];
char *host = "127.0.0.1";
int port = 0;
pid_t pid = 0;
int sockfd = 0;
struct sockaddr_in serv_addr;
struct hostent* host_info;
long host_addr;
/* Get rid of an existing managed-slapd processs */
pid = ReadPid(SLAPD_LOCKFILE);
if (pid > 0) {
if (kill(pid, 0) == 0 || errno != ESRCH) {
/* Existing process */
if (killExisting) {
if (kill(pid, SIGKILL) == 0) {
XplDelay(1000);
fprintf(stderr, "bongomanager: killed existing managed-slapd process.\n");
} else if (errno != ESRCH) {
fprintf(stderr, "bongomanager: could not kill existing managed-slapd process.\n");
return 1;
}
} else {
fprintf(stderr, "bongomanager: managed-slapd appears to be running as pid %d\n"
"bongomanager: if this is definitely the bongo slapd, you can run with -e to kill it\n",
pid);
return 1;
}
}
}
/* read config */
if (!MsgGetConfigProperty((unsigned char *) buf,
(unsigned char *) MSGSRV_CONFIG_PROP_MANAGED_SLAPD_PORT)) {
fprintf(stderr, "bongomanager: error reading managed slapd port from config file.\n\r");
return 1;
}
port = atoi(buf);
if (!MsgGetConfigProperty((unsigned char *) buf,
(unsigned char *) MSGSRV_CONFIG_PROP_MANAGED_SLAPD_PATH)) {
fprintf(stderr, "Error reading managed slapd path from config file.\n\r");
return 1;
}
snprintf(url, MDB_MAX_OBJECT_CHARS, "ldap://%s:%d", host, port);
printf("bongomanager: starting managed slapd...\n");
pid = fork();
if (!pid) {
/* We would pass the -u argument to slapd to set its uid here,
but at this point in bongomanager we've already dropped
privs to BONGO_USER. */
execl(buf, buf,
"-f", XPL_DEFAULT_CONF_DIR "/bongo-slapd.conf",
"-h", url,
"-n", "bongo-slapd",
NULL);
exit(1);
}
waitpid(pid, &status, 0);
if (!WIFEXITED(status)) {
/* slapd process didn't exit normally */
return 1;
} else if (WEXITSTATUS(status)) {
/* slapd process exited with an error */
return 1;
}
/* wait until the slapd process is reachable */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
return 1;
}
host_info = gethostbyname(host);
memcpy(&host_addr, host_info->h_addr, host_info->h_length);
serv_addr.sin_addr.s_addr = host_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
while (1) {
err= connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (err == -1) {
int error = errno;
if (error == ECONNREFUSED) {
sleep(1);
continue;
} else {
fprintf(stderr, "bongomanager: error connecting to slapd: %s\n", strerror(error));
return 1;
}
}
SlapdPID = ReadPid(SLAPD_LOCKFILE);
printf("bongomanager: slapd started\n");
break;
}
close(sockfd);
return err;
}
static int
StopSlapd(void)
{
int err = 0;
if (kill(SlapdPID, SIGTERM) != 0) {
unlink(SLAPD_LOCKFILE);
err = 0;
} else {
err = 1;
}
return err;
}
static void
ParentSignalHandler(int signo)
{
switch (signo) {
case SIGCHLD:
ChildError = TRUE;
case SIGUSR1:
Exiting = TRUE;
}
}
static int
Daemonize(void)
{
pid_t pid;
/* these have to be before the fork, otherwise the child could
* signal before the parent has set them */
signal(SIGUSR1, ParentSignalHandler);
signal(SIGCHLD, ParentSignalHandler);
pid = fork();
if (pid < 0) {
fprintf(stderr, "bongomanager: could not fork into background (%d): %s\n",
errno, strerror(errno));
return 1;
} else if (pid != 0) {
/* wait for child to signal us that agents have been started, or it had an error */
while (!Exiting) {
XplDelay(1000);
}
if (ChildError) {
int status;
waitpid(pid, &status, 0);
exit(WEXITSTATUS(status));
}
printf("bongomanager: running in background\n");
_exit(0);
}
signal(SIGUSR1, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
setsid();
chdir("/");
umask(0);
return 0;
}
static int
SignalParent()
{
return kill (getppid(), SIGUSR1);
}
int
main(int argc, char **argv)
{
int numWaiting;
int lastNumWaiting;
int forceShutdownTime;
BOOL daemonize;
BOOL force;
BOOL keepAlive;
BOOL shutdown;
BOOL reload;
BOOL slapdOnly;
BOOL killExistingSlapd;
char buf[CONN_BUFSIZE];
BOOL droppedPrivs = FALSE;
BOOL unlockFile = FALSE;
BOOL startLdap = FALSE;
XplInit();
XplSaveRandomSeed(); /// is this appropriate?
if (getuid() == 0) {
if (XplSetEffectiveUser(MsgGetUnprivilegedUser()) < 0) {
fprintf(stderr, "bongomanager: could not drop to unprivileged user '%s'\n", MsgGetUnprivilegedUser());
exit(1);
}
droppedPrivs = TRUE;
}
if (!ParseArgs(argc, argv, &daemonize, &force, &keepAlive, &shutdown, &reload, &slapdOnly, &killExistingSlapd)) {
ShowHelp();
exit(1);
}
if (!droppedPrivs) {
fprintf(stderr, "bongomanager: must be run by root\n");
exit(1);
}
if (reload) {
pid_t pid = ReadPid(LOCKFILE);
if (pid <= 0) {
fprintf(stderr, "bongomanager: could not open pid file '%s'\n", LOCKFILE);
exit(1);
}
if (kill(pid, SIGUSR1) == -1) {
if (errno == ESRCH) {
fprintf (stderr, "bongomanager: bongomanager does not appear to be running.\n");
} else {
fprintf (stderr, "bongomanager: unable to reload services: %s\n", strerror(errno));
}
exit(1);
}
exit(0);
}
if (shutdown) {
pid_t pid = ReadPid(LOCKFILE);
if (pid <= 0) {
fprintf(stderr, "bongomanager: could not open pid file '%s'\n", LOCKFILE);
exit(1);
}
if (kill(pid, SIGTERM) == -1) {
if (errno == ESRCH) {
fprintf (stderr, "bongomanager: bongomanager does not appear to be running.\n");
} else {
fprintf (stderr, "bongomanager: unable to shut down services: %s\n", strerror(errno));
}
exit(1);
}
WaitOnPidFile();
exit(0);
}
if (daemonize) {
if (Daemonize()) {
exit(1);
}
}
get_lock:
if (Lock(force) == -1) {
if (errno == EEXIST) {
pid_t pid = ReadPid(LOCKFILE);
if (kill(pid, 0) != -1 || errno != ESRCH) {
fprintf(stderr, "bongomanager: another bongomanager process appears to be running.\n");
fprintf(stderr, "bongomanager: run with -s to stop an existing process, or -f to ignore the existing pidfile.\n");
} else if (!force) {
fprintf(stderr, "bongomanager: removing stale lock file in %s.\n", LOCKFILE);
force = TRUE;
goto get_lock;
} else {
fprintf (stderr, "bongomanager: could not remove stale lock file in %s.\n", LOCKFILE);
}
} else if (errno == EPERM) {
fprintf(stderr, "bongomanager: %s user does not have permission to create a lock file in %s\n",
MsgGetUnprivilegedUser(), XPL_DEFAULT_WORK_DIR);
} else {
fprintf(stderr, "bongomanager: could not create lock file: %s\n", strerror(errno));
}
goto err_handler;
}
unlockFile = TRUE;
if (!MemoryManagerOpen("bongomanager")) {
fprintf(stderr, "bongomanager: failed to initialize memory manager. Exiting\n");
goto err_handler;
}
if (!MsgGetConfigProperty(ServerDN, MSGSRV_CONFIG_PROP_MESSAGING_SERVER)) {
fprintf(stderr, "bongomanager: Couldn't read the server DN from bongo.conf.\r\n");
goto err_handler;
}
if (MsgGetConfigProperty((unsigned char *) buf,
(unsigned char *) MSGSRV_CONFIG_PROP_MANAGED_SLAPD)) {
startLdap = atoi(buf);
}
if (startLdap) {
int err;
err = StartSlapd(killExistingSlapd);
if (err != 0) {
fprintf(stderr, "bongomanager: managed slapd process failed to start.\n");
goto err_handler;
}
} else if (slapdOnly) {
fprintf(stderr, "bongomanager: -l only works with a managed-slapd database.\n");
goto err_handler;
}
if (!slapdOnly) {
if (!MDBInit()) {
fprintf(stderr, "bongomanager: unable to intialize directory access.\n");
goto err_handler;
}
DirectoryHandle = MsgGetSystemDirectoryHandle();
if (DirectoryHandle == NULL) {
fprintf(stderr, "bongomanager: unable to initialize messaging library.\n");
goto err_handler;
}
if (!GetAgents()) {
fprintf(stderr, "bongomanager: no configured agents.\n");
goto err_handler;
}
}
signal(SIGTERM, SignalHandler);
signal(SIGINT, SignalHandler);
signal(SIGCHLD, SignalHandler);
signal(SIGUSR1, SignalHandler);
if (!slapdOnly) {
StartAgents(FALSE, FALSE);
}
if (daemonize) {
SignalParent();
}
while(!Exiting) {
XplDelay(10000);
if (!slapdOnly) {
Reap();
if (ReloadNow) {
ResetCrashiness();
}
if ((ReloadNow || keepAlive) && !Exiting) {
StartAgents(!ReloadNow, TRUE);
}
ReloadNow = FALSE;
}
}
printf("bongomanager: shutting down...\n");
if (!slapdOnly) {
numWaiting = lastNumWaiting = 0;
forceShutdownTime = time(NULL) + 10;
while ((numWaiting = AgentsStillRunning()) > 0) {
lastNumWaiting = numWaiting;
if (forceShutdownTime < time(NULL)) {
fprintf(stderr, "bongomanager: '");
BlameAgents();
fprintf(stderr, "' stubbornly refusing to die, insisting.\n");
killpg(LeaderPID, SIGKILL);
forceShutdownTime = time(NULL) + 5;
}
XplDelay(500);
Reap();
}
}
Unlock(LOCKFILE);
if (SlapdPID > 0) {
StopSlapd();
}
printf("bongomanager: shutdown complete.\n");
return 0;
err_handler:
if (SlapdPID > 0) {
StopSlapd();
}
if (unlockFile) {
Unlock(LOCKFILE);
}
exit(1);
}