diff options
Diffstat (limited to 'server/monitor')
-rw-r--r-- | server/monitor/monitor.c | 355 | ||||
-rw-r--r-- | server/monitor/monitor.h | 4 | ||||
-rw-r--r-- | server/monitor/monitor_interfaces.h | 1 |
3 files changed, 234 insertions, 126 deletions
diff --git a/server/monitor/monitor.c b/server/monitor/monitor.c index 8ecb8733..1247842f 100644 --- a/server/monitor/monitor.c +++ b/server/monitor/monitor.c @@ -81,6 +81,24 @@ struct mt_svc { struct tevent_timer *ping_ev; }; +struct config_file_callback { + int wd; + int retries; + monitor_reconf_fn fn; + char *filename; + time_t modified; + struct config_file_callback *next; + struct config_file_callback *prev; +}; + +struct config_file_ctx { + TALLOC_CTX *parent_ctx; + struct tevent_timer *timer; + bool needs_update; + struct mt_ctx *mt_ctx; + struct config_file_callback *callbacks; +}; + struct mt_ctx { struct tevent_context *ev; struct confdb_ctx *cdb; @@ -90,24 +108,11 @@ struct mt_ctx { char **services; struct mt_svc *svc_list; struct sbus_srv_ctx *sbus_srv; - + struct config_file_ctx *file_ctx; + int inotify_fd; int service_id_timeout; }; -struct config_file_ctx { - TALLOC_CTX *parent_ctx; - struct confdb_ctx *cdb; - struct tevent_context *ev; - int fd; - int retries; - int wd; - char *filename; - time_t modified; - bool needs_update; - confdb_reconf_fn reconf_fn; - void *reconf_pvt; -}; - static int start_service(struct mt_svc *mt_svc); static int dbus_service_init(struct sbus_conn_ctx *conn_ctx, void *data); @@ -129,7 +134,8 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name, static int add_new_service(struct mt_ctx *ctx, const char *name); static int add_new_provider(struct mt_ctx *ctx, const char *name); -static int monitor_signal_reconf(struct config_file_ctx *file_ctx); +static int monitor_signal_reconf(struct config_file_ctx *file_ctx, + const char *filename); static int update_monitor_config(struct mt_ctx *ctx); static int monitor_cleanup(void); @@ -509,14 +515,14 @@ done: dbus_message_unref(reply); } -static int monitor_signal_reconf(struct config_file_ctx *file_ctx) +static int monitor_signal_reconf(struct config_file_ctx *file_ctx, + const char *filename) { int ret; - struct mt_ctx *ctx = talloc_get_type(file_ctx->reconf_pvt, struct mt_ctx); DEBUG(1, ("Configuration has changed. Reloading.\n")); /* Update the confdb configuration */ - ret = confdb_init_db(file_ctx->filename, file_ctx->cdb); + ret = confdb_init_db(filename, file_ctx->mt_ctx->cdb); if (ret != EOK) { DEBUG(0, ("Could not reload configuration!")); kill(getpid(), SIGTERM); @@ -524,10 +530,24 @@ static int monitor_signal_reconf(struct config_file_ctx *file_ctx) } /* Update the monitor's configuration and signal children */ - return update_monitor_config(ctx); + return update_monitor_config(file_ctx->mt_ctx); } -static int service_signal_reload(struct mt_svc *svc) +static int service_signal_dns_reload(struct mt_svc *svc); +int monitor_update_resolv(struct config_file_ctx *file_ctx, + const char *filename) +{ + struct mt_svc *cur_svc; + DEBUG(2, ("Resolv.conf has been updated. Reloading.\n")); + + /* Signal all services to reload their DNS configuration */ + for(cur_svc = file_ctx->mt_ctx->svc_list; cur_svc; cur_svc = cur_svc->next) { + service_signal_dns_reload(cur_svc); + } + return EOK; +} + +static int service_signal(struct mt_svc *svc, const char *svc_signal) { DBusMessage *msg; dbus_bool_t dbret; @@ -544,7 +564,7 @@ static int service_signal_reload(struct mt_svc *svc) * order a service to reload that hasn't started * yet. */ - DEBUG(1,("Could not reload service [%s].\n", svc->name)); + DEBUG(1,("Could not signal service [%s].\n", svc->name)); return EIO; } @@ -552,7 +572,7 @@ static int service_signal_reload(struct mt_svc *svc) msg = dbus_message_new_method_call(NULL, SERVICE_PATH, SERVICE_INTERFACE, - SERVICE_METHOD_RELOAD); + svc_signal); if (!msg) { DEBUG(0,("Out of memory?!\n")); monitor_kill_service(svc); @@ -577,6 +597,15 @@ static int service_signal_reload(struct mt_svc *svc) return EOK; } +static int service_signal_reload(struct mt_svc *svc) +{ + return service_signal(svc, SERVICE_METHOD_RELOAD); +} +static int service_signal_dns_reload(struct mt_svc *svc) +{ + return service_signal(svc, SERVICE_METHOD_RES_INIT); +} + static int check_domain_ranges(struct sss_domain_info *domains) { struct sss_domain_info *dom = domains, *other = NULL; @@ -1210,6 +1239,10 @@ static void config_file_changed(struct tevent_context *ev, file_ctx->needs_update = 1; } +struct rewatch_ctx { + struct config_file_callback *cb; + struct config_file_ctx *file_ctx; +}; static void rewatch_config_file(struct tevent_context *ev, struct tevent_timer *te, struct timeval t, void *ptr); @@ -1224,6 +1257,8 @@ static void process_config_file(struct tevent_context *ev, ssize_t len, total_len; ssize_t event_size; struct config_file_ctx *file_ctx; + struct config_file_callback *cb; + struct rewatch_ctx *rw_ctx; event_size = sizeof(struct inotify_event); file_ctx = talloc_get_type(ptr, struct config_file_ctx); @@ -1241,7 +1276,8 @@ static void process_config_file(struct tevent_context *ev, total_len = 0; while (total_len < event_size) { - len = read(file_ctx->fd, buf+total_len, event_size-total_len); + len = read(file_ctx->mt_ctx->inotify_fd, buf+total_len, + event_size-total_len); if (len == -1 && errno != EINTR) { DEBUG(0, ("Critical error reading inotify file descriptor.\n")); talloc_free(tmp_ctx); @@ -1259,7 +1295,7 @@ static void process_config_file(struct tevent_context *ev, name = talloc_size(tmp_ctx, len); total_len = 0; while (total_len < in_event->len) { - len = read(file_ctx->fd, &name, in_event->len); + len = read(file_ctx->mt_ctx->inotify_fd, &name, in_event->len); if (len == -1 && errno != EINTR) { DEBUG(0, ("Critical error reading inotify file descriptor.\n")); talloc_free(tmp_ctx); @@ -1271,6 +1307,16 @@ static void process_config_file(struct tevent_context *ev, talloc_free(tmp_ctx); + for (cb = file_ctx->callbacks; cb; cb = cb->next) { + if (cb->wd == in_event->wd) { + break; + } + } + if (!cb) { + DEBUG(0, ("Unknown watch descriptor\n")); + return; + } + if (in_event->mask & IN_IGNORED) { /* Some text editors will move a new file on top of the * existing one instead of modifying it. In this case, @@ -1283,18 +1329,28 @@ static void process_config_file(struct tevent_context *ev, tv.tv_sec = t.tv_sec+5; tv.tv_usec = t.tv_usec; - file_ctx->retries = 0; - tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, file_ctx); + cb->retries = 0; + rw_ctx = talloc(file_ctx, struct rewatch_ctx); + if(!rw_ctx) { + DEBUG(0, ("Could not restore inotify watch. Quitting!\n")); + close(file_ctx->mt_ctx->inotify_fd); + kill(getpid(), SIGTERM); + return; + } + rw_ctx->cb = cb; + rw_ctx->file_ctx = file_ctx; + + tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx); if (te == NULL) { DEBUG(0, ("Could not restore inotify watch. Quitting!\n")); - close(file_ctx->fd); + close(file_ctx->mt_ctx->inotify_fd); kill(getpid(), SIGTERM); } return; } /* Tell the monitor to signal the children */ - file_ctx->reconf_fn(file_ctx); + cb->fn(file_ctx, cb->filename); file_ctx->needs_update = 0; } @@ -1305,42 +1361,50 @@ static void rewatch_config_file(struct tevent_context *ev, int err; struct tevent_timer *tev = NULL; struct timeval tv; + struct config_file_callback *cb; + struct rewatch_ctx *rw_ctx; struct config_file_ctx *file_ctx; - file_ctx = talloc_get_type(ptr, struct config_file_ctx); - file_ctx->retries++; + + rw_ctx = talloc_get_type(ptr, struct rewatch_ctx); + + cb = rw_ctx->cb; + file_ctx = rw_ctx->file_ctx; /* Retry six times at five-second intervals before giving up */ - if (file_ctx->retries > 6) { + cb->retries++; + if (cb->retries > 6) { DEBUG(0, ("Could not restore inotify watch. Quitting!\n")); - close(file_ctx->fd); + close(file_ctx->mt_ctx->inotify_fd); kill(getpid(), SIGTERM); } - file_ctx->wd = inotify_add_watch(file_ctx->fd, file_ctx->filename, - IN_MODIFY); - if (file_ctx->wd < 0) { + cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd, + cb->filename, IN_MODIFY); + if (cb->wd < 0) { err = errno; tv.tv_sec = t.tv_sec+5; tv.tv_usec = t.tv_usec; DEBUG(1, ("Could not add inotify watch for file [%s]. Error [%d:%s]\n", - file_ctx->filename, err, strerror(err))); + cb->filename, err, strerror(err))); - tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, file_ctx); + tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx); if (te == NULL) { DEBUG(0, ("Could not restore inotify watch. Quitting!\n")); - close(file_ctx->fd); + close(file_ctx->mt_ctx->inotify_fd); kill(getpid(), SIGTERM); } return; } - file_ctx->retries = 0; + cb->retries = 0; /* Tell the monitor to signal the children */ - file_ctx->reconf_fn(file_ctx); + cb->fn(file_ctx, cb->filename); + + talloc_free(rw_ctx); file_ctx->needs_update = 0; } #endif @@ -1352,90 +1416,113 @@ static void poll_config_file(struct tevent_context *ev, int ret, err; struct stat file_stat; struct timeval tv; - struct tevent_timer *timer; - struct config_file_ctx *file_ctx = - talloc_get_type(ptr,struct config_file_ctx); + struct config_file_ctx *file_ctx; + struct config_file_callback *cb; - ret = stat(file_ctx->filename, &file_stat); - if (ret < 0) { - err = errno; - DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n", - file_ctx->filename, err, strerror(err))); - /* TODO: If the config file is missing, should we shut down? */ - return; - } + file_ctx = talloc_get_type(ptr,struct config_file_ctx); - if (file_stat.st_mtime != file_ctx->modified) { - /* Parse the configuration file and signal the children */ - /* Note: this will fire if the modification time changes into the past - * as well as the future. - */ - DEBUG(1, ("Config file changed\n")); - file_ctx->modified = file_stat.st_mtime; + for (cb = file_ctx->callbacks; cb; cb = cb->next) { + ret = stat(cb->filename, &file_stat); + if (ret < 0) { + err = errno; + DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n", + cb->filename, err, strerror(err))); + /* TODO: If the config file is missing, should we shut down? */ + return; + } + + if (file_stat.st_mtime != cb->modified) { + /* Parse the configuration file and signal the children */ + /* Note: this will fire if the modification time changes into the past + * as well as the future. + */ + DEBUG(1, ("Config file changed\n")); + cb->modified = file_stat.st_mtime; - /* Tell the monitor to signal the children */ - file_ctx->reconf_fn(file_ctx); + /* Tell the monitor to signal the children */ + cb->fn(file_ctx, cb->filename); + } } gettimeofday(&tv, NULL); tv.tv_sec += CONFIG_FILE_POLL_INTERVAL; tv.tv_usec = 0; - timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv, + file_ctx->timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv, poll_config_file, file_ctx); - if (!timer) { + if (!file_ctx->timer) { DEBUG(0, ("Error: Config file no longer monitored for changes!")); } } -static int try_inotify(struct config_file_ctx *file_ctx) +static int try_inotify(struct config_file_ctx *file_ctx, const char *filename, + monitor_reconf_fn fn) { #ifdef HAVE_SYS_INOTIFY_H int err, fd_args, ret; struct tevent_fd *tfd; + struct config_file_callback *cb; + + /* Monitoring the file descriptor should be global */ + if (!file_ctx->mt_ctx->inotify_fd) { + /* Set up inotify to monitor the config file for changes */ + file_ctx->mt_ctx->inotify_fd = inotify_init(); + if (file_ctx->mt_ctx->inotify_fd < 0) { + err = errno; + DEBUG(0, ("Could not initialize inotify, error [%d:%s]\n", + err, strerror(err))); + return err; + } - /* Set up inotify to monitor the config file for changes */ - file_ctx->fd = inotify_init(); - if (file_ctx->fd < 0) { - err = errno; - DEBUG(0, ("Could not initialize inotify, error [%d:%s]\n", - err, strerror(err))); - return err; - } + fd_args = fcntl(file_ctx->mt_ctx->inotify_fd, F_GETFL, NULL); + if (fd_args < 0) { + /* Could not set nonblocking */ + close(file_ctx->mt_ctx->inotify_fd); + return EINVAL; + } - fd_args = fcntl(file_ctx->fd, F_GETFL, NULL); - if (fd_args < 0) { - /* Could not set nonblocking */ - close(file_ctx->fd); - return EINVAL; + fd_args |= O_NONBLOCK; + ret = fcntl(file_ctx->mt_ctx->inotify_fd, F_SETFL, fd_args); + if (ret < 0) { + /* Could not set nonblocking */ + close(file_ctx->mt_ctx->inotify_fd); + return EINVAL; + } + + /* Add the inotify file descriptor to the TEvent context */ + tfd = tevent_add_fd(file_ctx->mt_ctx->ev, file_ctx, + file_ctx->mt_ctx->inotify_fd, + TEVENT_FD_READ, config_file_changed, + file_ctx); + if (!tfd) { + close(file_ctx->mt_ctx->inotify_fd); + return EIO; + } } - fd_args |= O_NONBLOCK; - ret = fcntl(file_ctx->fd, F_SETFL, fd_args); - if (ret < 0) { - /* Could not set nonblocking */ - close(file_ctx->fd); - return EINVAL; + cb = talloc_zero(file_ctx, struct config_file_callback); + if(!cb) { + close(file_ctx->mt_ctx->inotify_fd); + return EIO; } - file_ctx->wd = inotify_add_watch(file_ctx->fd, file_ctx->filename, - IN_MODIFY); - if (file_ctx->wd < 0) { + cb->filename = talloc_strdup(cb, filename); + if (!cb->filename) { + close(file_ctx->mt_ctx->inotify_fd); + return ENOMEM; + } + cb->wd = inotify_add_watch(file_ctx->mt_ctx->inotify_fd, + cb->filename, IN_MODIFY); + if (cb->wd < 0) { err = errno; DEBUG(0, ("Could not add inotify watch for file [%s]. Error [%d:%s]\n", - file_ctx->filename, err, strerror(err))); - close(file_ctx->fd); + cb->filename, err, strerror(err))); + close(file_ctx->mt_ctx->inotify_fd); return err; } + cb->fn = fn; + + DLIST_ADD(file_ctx->callbacks, cb); - /* Add the inotify file descriptor to the TEvent context */ - tfd = tevent_add_fd(file_ctx->ev, file_ctx, file_ctx->fd, - TEVENT_FD_READ, config_file_changed, - file_ctx); - if (!tfd) { - inotify_rm_watch(file_ctx->fd, file_ctx->wd); - close(file_ctx->fd); - return EIO; - } return EOK; #else return EINVAL; @@ -1443,19 +1530,14 @@ static int try_inotify(struct config_file_ctx *file_ctx) } static int monitor_config_file(TALLOC_CTX *mem_ctx, - struct confdb_ctx *cdb, - struct tevent_context *ev, - const char *file, - confdb_reconf_fn fn, - void *reconf_pvt) + struct mt_ctx *ctx, + const char *file, + monitor_reconf_fn fn) { int ret, err; struct timeval tv; - struct stat file_stat; - struct config_file_ctx *file_ctx; - - struct tevent_timer *timer; + struct config_file_callback *cb = NULL; ret = stat(file, &file_stat); if (ret < 0) { @@ -1464,28 +1546,41 @@ static int monitor_config_file(TALLOC_CTX *mem_ctx, file, err, strerror(err))); return err; } + if (!ctx->file_ctx) { + ctx->file_ctx = talloc_zero(mem_ctx, struct config_file_ctx); + if (!ctx->file_ctx) return ENOMEM; - file_ctx = talloc_zero(mem_ctx, struct config_file_ctx); - if (!file_ctx) return ENOMEM; - - file_ctx->parent_ctx = mem_ctx; - file_ctx->cdb = cdb; - file_ctx->filename = talloc_strdup(file_ctx, file); - file_ctx->modified = file_stat.st_mtime; - file_ctx->reconf_fn = fn; - file_ctx->reconf_pvt = reconf_pvt; - file_ctx->ev = ev; - - ret = try_inotify(file_ctx); + ctx->file_ctx->parent_ctx = mem_ctx; + ctx->file_ctx->mt_ctx = ctx; + } + ret = try_inotify(ctx->file_ctx, file, fn); if (ret != EOK) { /* Could not monitor file with inotify, fall back to polling */ - gettimeofday(&tv, NULL); - tv.tv_sec += CONFIG_FILE_POLL_INTERVAL; - tv.tv_usec = 0; - timer = tevent_add_timer(ev, mem_ctx, tv, poll_config_file, file_ctx); - if (!timer) { - talloc_free(file_ctx); - return EIO; + cb = talloc_zero(ctx->file_ctx, struct config_file_callback); + if (!cb) { + talloc_free(ctx->file_ctx); + return ENOMEM; + } + cb->filename = talloc_strdup(cb, file); + if (!cb->filename) { + talloc_free(ctx->file_ctx); + return ENOMEM; + } + cb->fn = fn; + cb->modified = file_stat.st_mtime; + + DLIST_ADD(ctx->file_ctx->callbacks, cb); + + if(!ctx->file_ctx->timer) { + gettimeofday(&tv, NULL); + tv.tv_sec += CONFIG_FILE_POLL_INTERVAL; + tv.tv_usec = 0; + ctx->file_ctx->timer = tevent_add_timer(ctx->ev, mem_ctx, tv, + poll_config_file, ctx->file_ctx); + if (!ctx->file_ctx->timer) { + talloc_free(ctx->file_ctx); + return EIO; + } } } @@ -1564,7 +1659,15 @@ int monitor_process_init(TALLOC_CTX *mem_ctx, } /* Watch for changes to the confdb config file */ - ret = monitor_config_file(ctx, cdb, event_ctx, config_file, monitor_signal_reconf, ctx); + ret = monitor_config_file(ctx, ctx, config_file, monitor_signal_reconf); + if (ret != EOK) { + talloc_free(ctx); + return ret; + } + + /* Watch for changes to the DNS resolv.conf */ + ret = monitor_config_file(ctx, ctx, RESOLV_CONF_PATH, + monitor_update_resolv); if (ret != EOK) { talloc_free(ctx); return ret; diff --git a/server/monitor/monitor.h b/server/monitor/monitor.h index 2a5218b1..0127bbff 100644 --- a/server/monitor/monitor.h +++ b/server/monitor/monitor.h @@ -22,8 +22,12 @@ #ifndef _MONITOR_H_ #define _MONITOR_H_ +#define RESOLV_CONF_PATH "/etc/resolv.conf" #define CONFIG_FILE_POLL_INTERVAL 5 /* seconds */ +typedef int (*monitor_reconf_fn) (struct config_file_ctx *file_ctx, + const char *filename); + int monitor_process_init(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, struct confdb_ctx *cdb, diff --git a/server/monitor/monitor_interfaces.h b/server/monitor/monitor_interfaces.h index 8fdafd61..05d1bb41 100644 --- a/server/monitor/monitor_interfaces.h +++ b/server/monitor/monitor_interfaces.h @@ -39,5 +39,6 @@ #define SERVICE_METHOD_PING "ping" #define SERVICE_METHOD_RELOAD "reloadConfig" #define SERVICE_METHOD_SHUTDOWN "shutDown" +#define SERVICE_METHOD_RES_INIT "resInit" #define SSSD_SERVICE_PIPE "private/sbus-monitor" |