monitor.c revision ba5e2d5e261e5f3ac6ce00227595f7265d2c715e
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher Service monitor
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher Copyright (C) Simo Sorce 2008
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher This program is free software; you can redistribute it and/or modify
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher it under the terms of the GNU General Public License as published by
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher the Free Software Foundation; either version 3 of the License, or
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher (at your option) any later version.
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher This program is distributed in the hope that it will be useful,
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher but WITHOUT ANY WARRANTY; without even the implied warranty of
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher GNU General Public License for more details.
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher You should have received a copy of the GNU General Public License
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher along with this program. If not, see <http://www.gnu.org/licenses/>.
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher/* Needed for res_init() */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher/* terminate the child after this interval by default if it
681742138b2afbbefa7f14de937beb438409208eSimo Sorce * doesn't shutdown on receiving SIGTERM */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher/* TODO: get the restart related values from config */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#define MONITOR_RESTART_CNT_INTERVAL_RESET 30
1e7c355a2d36eb7b942b5111c96eb2a2285d49ccStephen Gallagher/* maximum allowed number of service restarts if the restarts
1e7c355a2d36eb7b942b5111c96eb2a2285d49ccStephen Gallagher * were less than MONITOR_RESTART_CNT_INTERVAL_RESET apart, which would
681742138b2afbbefa7f14de937beb438409208eSimo Sorce * indicate a crash after startup or after every request */
1e7c355a2d36eb7b942b5111c96eb2a2285d49ccStephen Gallagher/* The services are restarted with a delay in case the restart was
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher * hitting a race condition where the DP is not ready yet either.
4fcc50e133f90cd4c5931a3ac48c84cb628b16fcMichal Zidek * The MONITOR_MAX_RESTART_DELAY defines the maximum delay between
e299638926171e0e92a36122aeff6611cd52418dStephen Gallagher/* name of the monitor server instance */
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#define SSSD_PIDFILE_PATH PID_PATH"/"MONITOR_NAME".pid"
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher/* Special value to leave the Kerberos Replay Cache set to use
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher * the libkrb5 defaults
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher#define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__"
681742138b2afbbefa7f14de937beb438409208eSimo Sorce/* Warning messages */
681742138b2afbbefa7f14de937beb438409208eSimo Sorce#define CONF_FILE_PERM_ERROR_MSG "Cannot read config file %s. Please check "\
681742138b2afbbefa7f14de937beb438409208eSimo Sorce "that the file is accessible only by the "\
681742138b2afbbefa7f14de937beb438409208eSimo Sorce "owner and owned by root.root.\n"
char *identity;
char *diag_cmd;
int kill_time;
bool svc_started;
int restarts;
int debug_level;
struct config_file_callback {
int wd;
int retries;
char *filename;
struct config_file_ctx {
bool needs_update;
struct mt_ctx {
char **services;
int num_services;
int started_services;
int inotify_fd;
int service_id_timeout;
bool check_children;
bool services_started;
const char *conf_path;
bool is_daemon;
const char *name,
int restarts);
const char *name,
int restarts);
static int monitor_cleanup(void);
struct mon_init_conn {
char *svc_name;
int ret;
if (!mini) {
return EINVAL;
if (!dbret) {
goto done;
while (svc) {
if (ret == 0) {
if (!svc) {
goto done;
if (ret) {
goto done;
done:
return EOK;
struct svc_spy {
if (!svc) {
if (!spy) {
return EOK;
const char *template)
char *copy;
char *p_copy;
char action;
return NULL;
goto done;
goto done;
goto done;
action = *n;
switch (action) {
goto done;
goto done;
goto done;
done:
return res;
char **args;
int ret;
int debug_fd;
char *diag_cmd;
if (pkc_pid != 0) {
svc,
int ret;
if (ret) {
goto done;
if (iter) {
goto done;
goto done;
errno = 0;
if (ret != 0) {
done:
return ret;
if (!to) {
return ENOMEM;
return EOK;
{ &mon_srv_iface_meta, 0 },
char *monitor_address;
int ret;
return ret;
return ret;
int ret;
return EOK;
svc,
tv,
svc);
return EOK;
int ret;
if (!reply) {
const char *filename)
int ret;
if(ret != 0) {
return EIO;
return EOK;
int ret;
return EOK;
return EIO;
return ENOMEM;
return ret;
while (dom) {
return EINVAL;
while (other) {
return EOK;
while (dom) {
count++;
return EINVAL;
return EOK;
char ***_services)
int ret;
char **domain_names;
size_t c;
char *conf_path;
char *id_provider;
bool add_pac = false;
return ENOMEM;
&domain_names);
goto done;
domain_names[c]);
goto done;
add_pac = true;
domain_names[c]);
goto done;
done:
return ret;
int ii;
for (i = 0; services[i]; i++) {
return services[i];
return NULL;
char *user_str;
return ret;
return ret;
return EOK;
int ret;
int timeout_seconds;
return ret;
return EINVAL;
return EINVAL;
return ret;
return ret;
return ret;
return ret;
return EOK;
return ret;
return ret;
return EOK;
int ret;
char *path;
if (!svc) {
return ENOMEM;
return ENOMEM;
return ENOMEM;
if (!path) {
return ENOMEM;
return ret;
return ENOMEM;
return ENOMEM;
return ENOMEM;
return ENOMEM;
return ENOMEM;
if (debug_to_file) {
return ENOMEM;
return ENOMEM;
return ret;
return EOK;
const char *name,
int restarts)
int ret;
return ret;
return ret;
int ret;
char *path;
if (!svc) {
return ENOMEM;
return ENOMEM;
return ENOMEM;
if (!path) {
return ENOMEM;
return ret;
return ret;
return ret;
return EIO;
return ENOMEM;
return ENOMEM;
return ENOMEM;
return ENOMEM;
return ENOMEM;
if (debug_to_file) {
return ENOMEM;
return ENOMEM;
return EOK;
const char *name,
int restarts)
int ret;
name);
return ret;
return ENOENT;
return ret;
int signum,
int count,
void *siginfo,
void *private_data)
static int monitor_cleanup(void)
int ret;
errno = 0;
return ret;
return EOK;
int status;
int kret;
bool killed;
killed = false;
errno = 0;
if (kret < 0) {
error = 0;
errno = 0;
killed = true;
} else if (pid != 0) {
error = 0;
killed = true;
if (!killed) {
} while (!killed);
#if HAVE_GETPGRP
error = 0;
errno = 0;
int signum,
int count,
void *siginfo,
void *private_data)
int ret;
if (ret == 0) {
int signum,
int count,
void *siginfo,
void *private_data)
int signum,
int count,
void *siginfo,
void *private_data)
const char *config_file,
const char *config_dir,
if(!ctx) {
return ENOMEM;
goto done;
goto done;
goto done;
if (ret != 0) {
goto done;
done:
return ret;
const char *file,
bool ignore_missing);
#ifdef HAVE_INOTIFY
if (!te) {
struct rewatch_ctx {
char *name;
if (!tmp_ctx) return;
if (!in_event) {
goto done;
errno = 0;
sizeof(struct inotify_event));
goto done;
if (!name) {
goto done;
errno = 0;
goto done;
if (!cb) {
goto done;
if(!rw_ctx) {
goto done;
goto done;
done:
int err;
if (ret < 0) {
#ifdef HAVE_INOTIFY
return err;
if (fd_args < 0) {
return EINVAL;
if (ret < 0) {
return EINVAL;
file_ctx);
if (!tfd) {
return EIO;
if(!cb) {
return ENOMEM;
return ENOMEM;
return err;
return EOK;
return EINVAL;
const char *file,
bool ignore_missing)
bool use_inotify;
if (ret < 0) {
return EOK;
return err;
true, &use_inotify);
return ret;
if (use_inotify) {
use_inotify = false;
if (!use_inotify) {
return ret;
const char *file,
bool ignore_missing)
if (ret < 0) {
return EOK;
return err;
if (!cb) {
return ENOMEM;
return ENOMEM;
return EIO;
return EOK;
int ret;
monitor_update_resolv, false);
"tevent_add_timer failed. resolv.conf will be ignored.\n");
"Monitor_config_file failed. resolv.conf will be ignored.\n");
const char *config_file)
char *rcachedir;
int num_providers;
int ret;
int error;
&rcachedir);
return ret;
errno = 0;
if (ret < 0) {
return EIO;
return EIO;
return EIO;
return EIO;
return EIO;
return ret;
/* Watch for changes to the DNS resolv.conf */
monitor_update_resolv, false);
return ret;
if (!tmp_ctx) {
return ENOMEM;
return ret;
return ret;
return ret;
num_providers = 0;
return ret;
if (num_providers > 0) {
return ret;
return EOK;
if (!mini) {
return ENOMEM;
return ENOMEM;
return ENOMEM;
return EOK;
char **args;
int restart_delay;
int opt;
int opt_daemon = 0;
int opt_interactive = 0;
int opt_version = 0;
int flags = 0;
int ret;
switch(opt) {
if (opt_version) {
return EXIT_SUCCESS;
if (uid != 0) {
if (!tmp_ctx) {
if (opt_interactive) {
if (opt_config_file) {
if (!config_file) {
if (debug_to_file) {
if (ret) {
#ifdef USE_KEYRING
switch (ret) {
case ENOENT:
case EEXIST:
case EOK:
&monitor);
switch (ret) {
case ERR_MISSING_CONF:
case EPERM:
case EACCES: