monitor.c revision 5ecc36322d9ccc9a9266263fcea8598ca89f4426
45d862b9c655542aa44c02958011065f6994f512Trond Norbye Service monitor
45d862b9c655542aa44c02958011065f6994f512Trond Norbye Copyright (C) Simo Sorce 2008
45d862b9c655542aa44c02958011065f6994f512Trond Norbye This program is free software; you can redistribute it and/or modify
45d862b9c655542aa44c02958011065f6994f512Trond Norbye it under the terms of the GNU General Public License as published by
45d862b9c655542aa44c02958011065f6994f512Trond Norbye the Free Software Foundation; either version 3 of the License, or
45d862b9c655542aa44c02958011065f6994f512Trond Norbye (at your option) any later version.
45d862b9c655542aa44c02958011065f6994f512Trond Norbye This program is distributed in the hope that it will be useful,
45d862b9c655542aa44c02958011065f6994f512Trond Norbye but WITHOUT ANY WARRANTY; without even the implied warranty of
45d862b9c655542aa44c02958011065f6994f512Trond Norbye MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45d862b9c655542aa44c02958011065f6994f512Trond Norbye GNU General Public License for more details.
45d862b9c655542aa44c02958011065f6994f512Trond Norbye You should have received a copy of the GNU General Public License
45d862b9c655542aa44c02958011065f6994f512Trond Norbye along with this program. If not, see <http://www.gnu.org/licenses/>.
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* Needed for res_init() */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* ping time cannot be less then once every few seconds or the
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * monitor will get crazy hammering children with messages */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* terminate the child after this interval by default if it
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * doesn't shutdown on receiving SIGTERM */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* TODO: get the restart related values from config */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* maximum allowed number of service restarts if the restarts
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * were less than MONITOR_RESTART_CNT_INTERVAL_RESET apart, which would
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * indicate a crash after startup or after every request */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* The services are restarted with a delay in case the restart was
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * hitting a race condition where the DP is not ready yet either.
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * The MONITOR_MAX_RESTART_DELAY defines the maximum delay between
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* name of the monitor server instance */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye#define SSSD_PIDFILE_PATH PID_PATH"/"MONITOR_NAME".pid"
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* Special value to leave the Kerberos Replay Cache set to use
45d862b9c655542aa44c02958011065f6994f512Trond Norbye * the libkrb5 defaults
45d862b9c655542aa44c02958011065f6994f512Trond Norbye#define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__"
45d862b9c655542aa44c02958011065f6994f512Trond Norbye/* Warning messages */
45d862b9c655542aa44c02958011065f6994f512Trond Norbye#define CONF_FILE_PERM_ERROR_MSG "Cannot read config file %s. Please check "\
45d862b9c655542aa44c02958011065f6994f512Trond Norbye "that the file is accessible only by the "\
45d862b9c655542aa44c02958011065f6994f512Trond Norbye "owner and owned by root.root.\n"
struct svc_spy;
enum mt_svc_type {
struct mt_svc {
char *provider;
char *command;
char *name;
char *identity;
int ping_time;
int kill_time;
bool svc_started;
int restarts;
int failed_pongs;
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;
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;
switch (ret) {
case EOK:
case ENXIO:
int ret;
goto done;
goto done;
done:
return ret;
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;
int ret;
int timeout_seconds;
return ret;
return EINVAL;
return EINVAL;
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;
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;
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,
if(!ctx) {
return ENOMEM;
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
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;
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,true);
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;
if (!intf) {
return ENOMEM;
int ret;
return ENXIO;
if (!msg) {
return ENOMEM;
return ret;
const char *dbus_error_name;
int type;
if (!svc) {
if (!reply) {
goto done;
switch (type) {
case DBUS_MESSAGE_TYPE_ERROR:
if (!dbus_error_name) {
done:
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:
switch (ret) {
case ERR_MISSING_CONF:
case EPERM:
case EACCES: