monitor.c revision 203b6bc547d6c59146be82686fe9e73d2b62dcaf
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/*
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen SSSD
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen Service monitor
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen Copyright (C) Simo Sorce 2008
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen This program is free software; you can redistribute it and/or modify
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen it under the terms of the GNU General Public License as published by
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen the Free Software Foundation; either version 3 of the License, or
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen (at your option) any later version.
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen This program is distributed in the hope that it will be useful,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen GNU General Public License for more details.
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen You should have received a copy of the GNU General Public License
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen*/
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include "util/util.h"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/types.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/wait.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/time.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/param.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <time.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <string.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#ifdef HAVE_SYS_INOTIFY_H
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/inotify.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#endif
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/types.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <sys/stat.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <unistd.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <fcntl.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen/* Needed for res_init() */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <netinet/in.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <arpa/nameser.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen#include <resolv.h>
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#include "popt.h"
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#include "tevent.h"
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen#include "confdb/confdb.h"
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen#include "confdb/confdb_setup.h"
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#include "collection.h"
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#include "ini_config.h"
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#include "db/sysdb.h"
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#include "monitor/monitor.h"
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen#include "dbus/dbus.h"
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen#include "sbus/sssd_dbus.h"
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen#include "monitor/monitor_interfaces.h"
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen/* ping time cannot be less then once every few seconds or the
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen * monitor will get crazy hammering children with messages */
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen#define MONITOR_DEF_PING_TIME 10
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainenint cmdline_debug_level;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstruct svc_spy;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstruct mt_svc {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *prev;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *next;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct sbus_connection *conn;
f3391d65cc830eab22ca6c5941774de682716edbTimo Sirainen struct svc_spy *conn_spy;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
f3391d65cc830eab22ca6c5941774de682716edbTimo Sirainen struct mt_ctx *mt_ctx;
f3391d65cc830eab22ca6c5941774de682716edbTimo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen char *provider;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen char *command;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen char *name;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen char *identity;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen pid_t pid;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen int ping_time;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen bool svc_started;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen int restarts;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen time_t last_restart;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen time_t last_ping;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen int failed_pongs;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen int debug_level;
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen struct tevent_timer *ping_ev;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen};
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainenstruct config_file_callback {
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen int wd;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen int retries;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen monitor_reconf_fn fn;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen char *filename;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen time_t modified;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen struct config_file_callback *next;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen struct config_file_callback *prev;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen};
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainenstruct config_file_ctx {
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen TALLOC_CTX *parent_ctx;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen struct tevent_timer *timer;
7da0a157dbcb64d3e97c01bcc87262bd944c6890Timo Sirainen bool needs_update;
7da0a157dbcb64d3e97c01bcc87262bd944c6890Timo Sirainen struct mt_ctx *mt_ctx;
7da0a157dbcb64d3e97c01bcc87262bd944c6890Timo Sirainen struct config_file_callback *callbacks;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen};
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstruct mt_ctx {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct tevent_context *ev;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct confdb_ctx *cdb;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen TALLOC_CTX *domain_ctx; /* Memory context for domain list */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct sss_domain_info *domains;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen TALLOC_CTX *service_ctx; /* Memory context for services */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen char **services;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *svc_list;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct sbus_connection *sbus_srv;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct config_file_ctx *file_ctx;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int inotify_fd;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int service_id_timeout;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen bool check_children;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen bool services_started;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct netlink_ctx *nlctx;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen const char *conf_path;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen};
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int start_service(struct mt_svc *mt_svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int monitor_service_init(struct sbus_connection *conn, void *data);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int service_send_ping(struct mt_svc *svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int service_signal_reset_offline(struct mt_svc *svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void ping_check(DBusPendingCall *pending, void *data);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int service_check_alive(struct mt_svc *svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void set_tasks_checker(struct mt_svc *srv);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void set_global_checker(struct mt_ctx *ctx);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int monitor_kill_service (struct mt_svc *svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int get_service_config(struct mt_ctx *ctx, const char *name,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc **svc_cfg);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainenstatic int get_provider_config(struct mt_ctx *ctx, const char *name,
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen struct mt_svc **svc_cfg);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainenstatic int add_new_service(struct mt_ctx *ctx, const char *name);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainenstatic int add_new_provider(struct mt_ctx *ctx, const char *name);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainenstatic int mark_service_as_started(struct mt_svc *svc);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainenstatic int monitor_cleanup(void);
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainenstatic void network_status_change_cb(enum network_change state,
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen void *cb_data)
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen{
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen struct mt_svc *iter;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen struct mt_ctx *ctx = (struct mt_ctx *) cb_data;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen if (state != NL_ROUTE_UP) return;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen DEBUG(9, ("A new route has appeared, signaling providers to reset offline status\n"));
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen for (iter = ctx->svc_list; iter; iter = iter->next) {
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen /* Don't signal services, only providers */
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen if (iter->provider) {
28f7485aaa7c5e0e3aa85d5a65d0dfc1c7ec7b89Timo Sirainen service_signal_reset_offline(iter);
28f7485aaa7c5e0e3aa85d5a65d0dfc1c7ec7b89Timo Sirainen }
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen }
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen}
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen/* dbus_get_monitor_version
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen * Return the monitor version over D-BUS */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int get_monitor_version(DBusMessage *message,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct sbus_connection *conn)
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen{
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen dbus_uint16_t version = MONITOR_VERSION;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen DBusMessage *reply;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen dbus_bool_t ret;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen reply = dbus_message_new_method_return(message);
e048e63fec8d21d4af0fd9d27dd3fe5dcedf18e6Timo Sirainen if (!reply) return ENOMEM;
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen ret = dbus_message_append_args(reply,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBUS_TYPE_UINT16, &version,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBUS_TYPE_INVALID);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!ret) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen dbus_message_unref(reply);
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen return EIO;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen /* send reply back */
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen sbus_conn_send_reply(conn, reply);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen dbus_message_unref(reply);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EOK;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstruct mon_init_conn {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_ctx *ctx;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct sbus_connection *conn;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct tevent_timer *timeout;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen};
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int add_svc_conn_spy(struct mt_svc *svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen/* registers a new client.
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * if operation is successful also sends back the Monitor version */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int client_registration(DBusMessage *message,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct sbus_connection *conn)
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen{
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen dbus_uint16_t version = MONITOR_VERSION;
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen struct mon_init_conn *mini;
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen struct mt_svc *svc;
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen void *data;
3568ea090b5a072e498438e74db23b98103ff2deTimo Sirainen DBusMessage *reply;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBusError dbus_error;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen dbus_uint16_t svc_ver;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen char *svc_name;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen dbus_bool_t dbret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen data = sbus_conn_get_private_data(conn);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen mini = talloc_get_type(data, struct mon_init_conn);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!mini) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("Connection holds no valid init data\n"));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EINVAL;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* First thing, cancel the timeout */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_zfree(mini->timeout);
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen dbus_error_init(&dbus_error);
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen dbret = dbus_message_get_args(message, &dbus_error,
b056d19b7a07400b897104b146c8768280d24009Timo Sirainen DBUS_TYPE_STRING, &svc_name,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBUS_TYPE_UINT16, &svc_ver,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBUS_TYPE_INVALID);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!dbret) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1, ("Failed to parse message, killing connection\n"));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen sbus_disconnect(conn);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* FIXME: should we just talloc_zfree(conn) ? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen goto done;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(4, ("Received ID registration: (%s,%d)\n", svc_name, svc_ver));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* search this service in the list */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc = mini->ctx->svc_list;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen while (svc) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen ret = strcasecmp(svc->identity, svc_name);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (ret == 0) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen break;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc = svc->next;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!svc) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("Unable to find peer [%s] in list of services,"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen " killing connection!\n", svc_name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen sbus_disconnect(conn);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* FIXME: should we just talloc_zfree(conn) ? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen goto done;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* Fill in svc structure with connection data */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->conn = mini->conn;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen ret = mark_service_as_started(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (ret) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1, ("Failed to mark service [%s]!\n", svc_name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen goto done;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* reply that all is ok */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen reply = dbus_message_new_method_return(message);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!reply) return ENOMEM;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen dbret = dbus_message_append_args(reply,
3a177dbf62af83209f1e33fc28c620ea1fc14adaTimo Sirainen DBUS_TYPE_UINT16, &version,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBUS_TYPE_INVALID);
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen if (!dbret) {
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen dbus_message_unref(reply);
58840b6cfccd09f0a7c6cd206437e52b6d8d386eTimo Sirainen return EIO;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* send reply back */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen sbus_conn_send_reply(conn, reply);
3a177dbf62af83209f1e33fc28c620ea1fc14adaTimo Sirainen dbus_message_unref(reply);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainendone:
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* init complete, get rid of temp init context */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_zfree(mini);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen return EOK;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstruct svc_spy {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *svc;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen};
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int svc_destructor(void *mem)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
58840b6cfccd09f0a7c6cd206437e52b6d8d386eTimo Sirainen struct mt_svc *svc = talloc_get_type(mem, struct mt_svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!svc) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* ?!?!? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* try to delist service */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->mt_ctx) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DLIST_REMOVE(svc->mt_ctx->svc_list, svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
3a177dbf62af83209f1e33fc28c620ea1fc14adaTimo Sirainen
58840b6cfccd09f0a7c6cd206437e52b6d8d386eTimo Sirainen /* svc is beeing freed, neutralize the spy */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->conn_spy) {
3a177dbf62af83209f1e33fc28c620ea1fc14adaTimo Sirainen talloc_set_destructor((TALLOC_CTX *)svc->conn_spy, NULL);
58840b6cfccd09f0a7c6cd206437e52b6d8d386eTimo Sirainen talloc_zfree(svc->conn_spy);
58840b6cfccd09f0a7c6cd206437e52b6d8d386eTimo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return 0;
58840b6cfccd09f0a7c6cd206437e52b6d8d386eTimo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int svc_spy_destructor(void *mem)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct svc_spy *spy = talloc_get_type(mem, struct svc_spy);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!spy) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* ?!?!? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return 0;
3a177dbf62af83209f1e33fc28c620ea1fc14adaTimo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* svc->conn has been freed, NULL the pointer in svc */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen spy->svc->conn_spy = NULL;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen spy->svc->conn = NULL;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int add_svc_conn_spy(struct mt_svc *svc)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct svc_spy *spy;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen spy = talloc(svc->conn, struct svc_spy);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!spy) return ENOMEM;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen spy->svc = svc;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_set_destructor((TALLOC_CTX *)spy, svc_spy_destructor);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->conn_spy = spy;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EOK;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int mark_service_as_started(struct mt_svc *svc)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_ctx *ctx = svc->mt_ctx;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *iter;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int ret;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen int i;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen DEBUG(5, ("Marking %s as started.\n", svc->name));
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen svc->svc_started = true;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen /* we need to attach a spy to the connection structure so that if some code
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen * frees it we can zero it out in the service structure. Otherwise we may
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen * try to access or even free, freed memory. */
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen ret = add_svc_conn_spy(svc);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen if (ret) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen DEBUG(0, ("Failed to attch spy\n"));
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen goto done;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen }
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen if (!ctx->services_started) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen /* check if all providers are up */
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen for (iter = ctx->svc_list; iter; iter = iter->next) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen if (iter->provider && !iter->svc_started) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen DEBUG(5, ("Still waiting on %s provider.\n", iter->name));
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen break;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen }
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen }
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen if (iter) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen /* there are still unstarted providers */
395aa4fe4639d13f37a470409d879f1c2b11254aTimo Sirainen goto done;
395aa4fe4639d13f37a470409d879f1c2b11254aTimo Sirainen }
395aa4fe4639d13f37a470409d879f1c2b11254aTimo Sirainen
395aa4fe4639d13f37a470409d879f1c2b11254aTimo Sirainen ctx->services_started = true;
453278403dbd2083b0c9a7aa5edb68d3f82ad4f6Timo Sirainen
453278403dbd2083b0c9a7aa5edb68d3f82ad4f6Timo Sirainen DEBUG(4, ("Now starting services!\n"));
395aa4fe4639d13f37a470409d879f1c2b11254aTimo Sirainen /* then start all services */
395aa4fe4639d13f37a470409d879f1c2b11254aTimo Sirainen for (i = 0; ctx->services[i]; i++) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen add_new_service(ctx, ctx->services[i]);
3a177dbf62af83209f1e33fc28c620ea1fc14adaTimo Sirainen }
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen }
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainendone:
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen return ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void services_startup_timeout(struct tevent_context *ev,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct tevent_timer *te,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct timeval t, void *ptr)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_ctx *ctx = talloc_get_type(ptr, struct mt_ctx);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int i;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
ca31fc1a8e48281c6882796fa7d4372acc2f97e5Timo Sirainen DEBUG(6, ("Handling timeout\n"));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!ctx->services_started) {
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen DEBUG(1, ("Providers did not start in time, "
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen "forcing services startup!\n"));
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen ctx->services_started = true;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen DEBUG(4, ("Now starting services!\n"));
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen /* then start all services */
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen for (i = 0; ctx->services[i]; i++) {
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen add_new_service(ctx, ctx->services[i]);
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen }
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen }
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen}
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainenstatic int add_services_startup_timeout(struct mt_ctx *ctx)
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen{
dfc96c43be0720d3a03faa1eb44032276cbf94cfTimo Sirainen struct tevent_timer *to;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen struct timeval tv;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen /* 5 seconds should be plenty */
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen tv = tevent_timeval_current_ofs(5, 0);
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen to = tevent_add_timer(ctx->ev, ctx, tv, services_startup_timeout, ctx);
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen if (!to) {
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen DEBUG(0,("Out of memory?!\n"));
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen return ENOMEM;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen }
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen return EOK;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen}
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainenstruct sbus_method monitor_methods[] = {
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen { MON_SRV_METHOD_VERSION, get_monitor_version },
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen { MON_SRV_METHOD_REGISTER, client_registration },
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen { NULL, NULL }
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen};
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainenstruct sbus_interface monitor_server_interface = {
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen MON_SRV_INTERFACE,
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen MON_SRV_PATH,
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen SBUS_DEFAULT_VTABLE,
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen monitor_methods,
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen NULL
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen};
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen/* monitor_dbus_init
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen * Set up the monitor service as a D-BUS Server */
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainenstatic int monitor_dbus_init(struct mt_ctx *ctx)
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen{
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen char *monitor_address;
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen int ret;
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen ret = monitor_get_sbus_address(ctx, &monitor_address);
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen if (ret != EOK) {
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen return ret;
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen }
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen ret = sbus_new_server(ctx, ctx->ev,
c44f7761bba61503d573eb950b9377f9d55ce2aaTimo Sirainen monitor_address, &monitor_server_interface,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen &ctx->sbus_srv, monitor_service_init, ctx);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_free(monitor_address);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void svc_try_restart(struct mt_svc *svc, time_t now)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DLIST_REMOVE(svc->mt_ctx->svc_list, svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->last_restart != 0) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if ((now - svc->last_restart) > 30) { /* TODO: get val from config */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* it was long ago reset restart threshold */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->restarts = 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* restart the process */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->restarts > 3) { /* TODO: get val from config */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("Process [%s], definitely stopped!\n", svc->name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_free(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* Shut down the current ping timer so it will restart
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * cleanly in start_service()
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_free(svc->ping_ev);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
c44f7761bba61503d573eb950b9377f9d55ce2aaTimo Sirainen ret = start_service(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (ret != EOK) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0,("Failed to restart service '%s'\n", svc->name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen talloc_free(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen svc->restarts++;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen svc->last_restart = now;
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen return;
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen}
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainenstatic void tasks_check_handler(struct tevent_context *ev,
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen struct tevent_timer *te,
34b858a4586db070d899e128a6fc76a4ea6050beTimo Sirainen struct timeval t, void *ptr)
34b858a4586db070d899e128a6fc76a4ea6050beTimo Sirainen{
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen struct mt_svc *svc = talloc_get_type(ptr, struct mt_svc);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen time_t now = time(NULL);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen bool process_alive = true;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen int ret;
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen ret = service_check_alive(svc);
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen switch (ret) {
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen case EOK:
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen /* all fine */
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen break;
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen case ECHILD:
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen DEBUG(1,("Process (%s) is stopped!\n", svc->name));
330865e1eb92715b34462af25c90c7308624c2afTimo Sirainen process_alive = false;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen break;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen default:
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen /* TODO: should we tear down it ? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1,("Checking for service %s(%d) failed!!\n",
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->name, svc->pid));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen break;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (process_alive) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen ret = service_send_ping(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen switch (ret) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen case EOK:
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen /* all fine */
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen break;
201437e07fd40d296377cc20ed1dab1f2777544aTimo Sirainen
201437e07fd40d296377cc20ed1dab1f2777544aTimo Sirainen case ENXIO:
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1,("Child (%s) not responding! (yet)\n", svc->name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen break;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen default:
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* TODO: should we tear it down ? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1,("Sending a message to service (%s) failed!!\n", svc->name));
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen break;
291ce16fffca75e8598a8c9dceb08613413dcb07Timo Sirainen }
c44f7761bba61503d573eb950b9377f9d55ce2aaTimo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->last_ping != 0) {
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen if ((now - svc->last_ping) > (svc->ping_time)) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->failed_pongs++;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen } else {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->failed_pongs = 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->failed_pongs > 3) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* too long since we last heard of this process */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1, ("Killing service [%s], not responding to pings!\n",
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->name));
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen monitor_kill_service(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen process_alive = false;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
bb2471ff14f01390b47cce63b407820b5547df1aTimo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->last_ping = now;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!process_alive) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc_try_restart(svc, now);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* all fine, set up the task checker again */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen set_tasks_checker(svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void set_tasks_checker(struct mt_svc *svc)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct tevent_timer *te = NULL;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct timeval tv;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen gettimeofday(&tv, NULL);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen tv.tv_sec += svc->ping_time;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen tv.tv_usec = 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen te = tevent_add_timer(svc->mt_ctx->ev, svc, tv, tasks_check_handler, svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (te == NULL) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("failed to add event, monitor offline for [%s]!\n",
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* FIXME: shutdown ? */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->ping_ev = te;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void global_checks_handler(struct tevent_context *ev,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct tevent_timer *te,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct timeval t, void *ptr)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_ctx *ctx = talloc_get_type(ptr, struct mt_ctx);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *svc;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int status;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen pid_t pid;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen if (!ctx->check_children) {
f663bdd9d345a86e6a7924d83319bd04b2fcb600Timo Sirainen goto done;
31159b598c4188211ff8f292daad1d23ee5db3cbTimo Sirainen }
31159b598c4188211ff8f292daad1d23ee5db3cbTimo Sirainen
31159b598c4188211ff8f292daad1d23ee5db3cbTimo Sirainen errno = 0;
31159b598c4188211ff8f292daad1d23ee5db3cbTimo Sirainen pid = waitpid(0, &status, WNOHANG);
31159b598c4188211ff8f292daad1d23ee5db3cbTimo Sirainen if (pid == 0) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen goto done;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (pid == -1) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("waitpid returned -1 (errno:%d[%s])\n",
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen errno, strerror(errno)));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen goto done;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* let's see if it is a known service, and try to restart it */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen for (svc = ctx->svc_list; svc; svc = svc->next) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->pid == pid) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen time_t now = time(NULL);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1, ("Service [%s] did exit\n", svc->name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc_try_restart(svc, now);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen goto done;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc == NULL) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("Unknown child (%d) did exit\n", pid));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainendone:
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen set_global_checker(ctx);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic void set_global_checker(struct mt_ctx *ctx)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct tevent_timer *te = NULL;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct timeval tv;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen gettimeofday(&tv, NULL);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen tv.tv_sec += 1; /* once a second */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen tv.tv_usec = 0;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen te = tevent_add_timer(ctx->ev, ctx, tv, global_checks_handler, ctx);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (te == NULL) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("failed to add global checker event! PANIC TIME!\n"));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* FIXME: is this right ? shoulkd we try to clean up first ?*/
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen exit(-1);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int monitor_kill_service (struct mt_svc *svc)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen ret = kill(svc->pid, SIGTERM);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (ret != EOK) {
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen DEBUG(0,("Sending signal to child (%s:%d) failed! "
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen "Ignore and pretend child is dead.\n",
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen svc->name, svc->pid));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return ret;
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen}
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainenstatic void reload_reply(DBusPendingCall *pending, void *data)
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen{
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen DBusMessage *reply;
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen struct mt_svc *svc = talloc_get_type(data, struct mt_svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen reply = dbus_pending_call_steal_reply(pending);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!reply) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* reply should never be null. This function shouldn't be called
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * until reply is valid or timeout has occurred. If reply is NULL
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * here, something is seriously wrong and we should bail out.
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(0, ("A reply callback was called but no reply was received"
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen " and no timeout occurred\n"));
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen /* Destroy this connection */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen sbus_disconnect(svc->conn);
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen dbus_pending_call_unref(pending);
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen return;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* TODO: Handle cases where the call has timed out or returned
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * with an error.
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen */
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen
90a2c5f48c5f88f07bbf0477e3023d2099252b92Timo Sirainen dbus_pending_call_unref(pending);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen dbus_message_unref(reply);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int service_signal_dns_reload(struct mt_svc *svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int monitor_update_resolv(struct config_file_ctx *file_ctx,
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen const char *filename)
29543188462c9348f365ec29115d777ffe4769d3Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen struct mt_svc *cur_svc;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(2, ("Resolv.conf has been updated. Reloading.\n"));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen ret = res_init();
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if(ret != 0) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EIO;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* Signal all services to reload their DNS configuration */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen for(cur_svc = file_ctx->mt_ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen service_signal_dns_reload(cur_svc);
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EOK;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen}
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainenstatic int service_signal(struct mt_svc *svc, const char *svc_signal)
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen{
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DBusMessage *msg;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen int ret;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (svc->provider && strcasecmp(svc->provider, "local") == 0) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* The local provider requires no signaling */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EOK;
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen }
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen if (!svc->conn) {
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen /* Avoid a race condition where we are trying to
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * order a service to reload that hasn't started
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen * yet.
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen */
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen DEBUG(1,("Could not signal service [%s].\n", svc->name));
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen return EIO;
3a2f2adf5679aa383a2cab09f739d59233cada95Timo Sirainen }
d71d05cf4417eaedb4d72491480a7d2bb46d8df3Timo Sirainen
e0aff4c7e3336ec4b5edbcfc3a72e1e118603ee2Timo Sirainen msg = dbus_message_new_method_call(NULL,
MONITOR_PATH,
MONITOR_INTERFACE,
svc_signal);
if (!msg) {
DEBUG(0,("Out of memory?!\n"));
monitor_kill_service(svc);
talloc_free(svc);
return ENOMEM;
}
ret = sbus_conn_send(svc->conn, msg,
svc->mt_ctx->service_id_timeout,
reload_reply, svc, NULL);
dbus_message_unref(msg);
return ret;
}
static int service_signal_dns_reload(struct mt_svc *svc)
{
return service_signal(svc, MON_CLI_METHOD_RES_INIT);
}
static int service_signal_offline(struct mt_svc *svc)
{
return service_signal(svc, MON_CLI_METHOD_OFFLINE);
}
static int service_signal_reset_offline(struct mt_svc *svc)
{
return service_signal(svc, MON_CLI_METHOD_RESET_OFFLINE);
}
static int service_signal_rotate(struct mt_svc *svc)
{
return service_signal(svc, MON_CLI_METHOD_ROTATE);
}
static int check_domain_ranges(struct sss_domain_info *domains)
{
struct sss_domain_info *dom = domains, *other = NULL;
uint32_t id_min, id_max;
while (dom) {
other = dom->next;
if (dom->id_max && dom->id_min > dom->id_max) {
DEBUG(1, ("Domain '%s' does not have a valid ID range\n",
dom->name));
return EINVAL;
}
while (other) {
id_min = MAX(dom->id_min, other->id_min);
id_max = MIN((dom->id_max ? dom->id_max : UINT32_MAX),
(other->id_max ? other->id_max : UINT32_MAX));
if (id_min <= id_max) {
DEBUG(1, ("Domains '%s' and '%s' overlap in range %u - %u\n",
dom->name, other->name, id_min, id_max));
}
other = other->next;
}
dom = dom->next;
}
return EOK;
}
static int check_local_domain_unique(struct sss_domain_info *domains)
{
uint8_t count = 0;
struct sss_domain_info *dom = domains;
while (dom) {
if (strcasecmp(dom->provider, "local") == 0) {
count++;
}
if (count > 1) {
break;
}
dom = dom->next;
}
if (count > 1) {
return EINVAL;
}
return EOK;
}
static char *check_services(char **services)
{
const char *known_services[] = { "nss", "pam", NULL };
int i;
int ii;
/* Check if services we are about to start are in the list if known */
for (i = 0; services[i]; i++) {
for (ii=0; known_services[ii]; ii++) {
if (strcasecmp(services[i], known_services[ii]) == 0) {
break;
}
}
if (known_services[ii] == NULL) {
return services[i];
}
}
return NULL;
}
int get_monitor_config(struct mt_ctx *ctx)
{
int ret;
int timeout_seconds;
char *badsrv = NULL;
ret = confdb_get_int(ctx->cdb, ctx,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_SBUS_TIMEOUT,
10, &timeout_seconds);
if (ret != EOK) {
return ret;
}
ctx->service_id_timeout = timeout_seconds * 1000; /* service_id_timeout is in ms */
ctx->service_ctx = talloc_new(ctx);
if(!ctx->service_ctx) {
return ENOMEM;
}
ret = confdb_get_string_as_list(ctx->cdb, ctx->service_ctx,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_ACTIVE_SERVICES,
&ctx->services);
if (ret != EOK) {
DEBUG(0, ("No services configured!\n"));
return EINVAL;
}
badsrv = check_services(ctx->services);
if (badsrv != NULL) {
DEBUG(0, ("Invalid service %s\n", badsrv));
return EINVAL;
}
ctx->domain_ctx = talloc_new(ctx);
if(!ctx->domain_ctx) {
return ENOMEM;
}
ret = confdb_get_domains(ctx->cdb, &ctx->domains);
if (ret != EOK) {
DEBUG(0, ("No domains configured.\n"));
return ret;
}
ret = check_local_domain_unique(ctx->domains);
if (ret != EOK) {
DEBUG(0, ("More than one local domain configured.\n"));
return ret;
}
/* Check UID/GID overlaps */
ret = check_domain_ranges(ctx->domains);
if (ret != EOK) {
return ret;
}
return EOK;
}
static int get_service_config(struct mt_ctx *ctx, const char *name,
struct mt_svc **svc_cfg)
{
int ret;
char *path;
struct mt_svc *svc;
*svc_cfg = NULL;
svc = talloc_zero(ctx, struct mt_svc);
if (!svc) {
return ENOMEM;
}
svc->mt_ctx = ctx;
talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
svc->name = talloc_strdup(svc, name);
if (!svc->name) {
talloc_free(svc);
return ENOMEM;
}
svc->identity = talloc_strdup(svc, name);
if (!svc->identity) {
talloc_free(svc);
return ENOMEM;
}
path = talloc_asprintf(svc, CONFDB_SERVICE_PATH_TMPL, svc->name);
if (!path) {
talloc_free(svc);
return ENOMEM;
}
ret = confdb_get_string(ctx->cdb, svc, path,
CONFDB_SERVICE_COMMAND,
NULL, &svc->command);
if (ret != EOK) {
DEBUG(0,("Failed to start service '%s'\n", svc->name));
talloc_free(svc);
return ret;
}
if (!svc->command) {
if (cmdline_debug_level == SSS_UNRESOLVED_DEBUG_LEVEL) {
svc->command = talloc_asprintf(svc, "%s/sssd_%s %s%s",
SSSD_LIBEXEC_PATH,
svc->name,
debug_timestamps?
"": "--debug-timestamps=0 ",
debug_to_file?
"--debug-to-files":"");
} else {
/* If the debug level was specified at the command-line,
* make sure to pass it into the children, overriding the
* config file.
*/
svc->command = talloc_asprintf(svc, "%s/sssd_%s -d %d%s%s",
SSSD_LIBEXEC_PATH,
svc->name,
cmdline_debug_level,
debug_timestamps ?
"" :
" --debug-timestamps=0",
debug_to_file ?
" --debug-to-files" :
"");
}
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
ret = confdb_get_int(ctx->cdb, svc, path,
CONFDB_SERVICE_TIMEOUT,
MONITOR_DEF_PING_TIME, &svc->ping_time);
if (ret != EOK) {
DEBUG(0,("Failed to start service '%s'\n", svc->name));
talloc_free(svc);
return ret;
}
/* 'timeout = 0' should be translated to the default */
if (svc->ping_time == 0) {
svc->ping_time = MONITOR_DEF_PING_TIME;
}
*svc_cfg = svc;
talloc_free(path);
return EOK;
}
static int add_new_service(struct mt_ctx *ctx, const char *name)
{
int ret;
struct mt_svc *svc;
ret = get_service_config(ctx, name, &svc);
if (ret != EOK) {
return ret;
}
ret = start_service(svc);
if (ret != EOK) {
DEBUG(0,("Failed to start service '%s'\n", svc->name));
talloc_free(svc);
}
return ret;
}
static int get_provider_config(struct mt_ctx *ctx, const char *name,
struct mt_svc **svc_cfg)
{
int ret;
char *path;
struct mt_svc *svc;
*svc_cfg = NULL;
svc = talloc_zero(ctx, struct mt_svc);
if (!svc) {
return ENOMEM;
}
svc->mt_ctx = ctx;
talloc_set_destructor((TALLOC_CTX *)svc, svc_destructor);
svc->name = talloc_strdup(svc, name);
if (!svc->name) {
talloc_free(svc);
return ENOMEM;
}
svc->identity = talloc_asprintf(svc, "%%BE_%s", svc->name);
if (!svc->identity) {
talloc_free(svc);
return ENOMEM;
}
path = talloc_asprintf(svc, CONFDB_DOMAIN_PATH_TMPL, name);
if (!path) {
talloc_free(svc);
return ENOMEM;
}
ret = confdb_get_string(ctx->cdb, svc, path,
CONFDB_DOMAIN_ID_PROVIDER,
NULL, &svc->provider);
if (ret != EOK) {
DEBUG(0, ("Failed to find ID provider from [%s] configuration\n", name));
talloc_free(svc);
return ret;
}
ret = confdb_get_string(ctx->cdb, svc, path,
CONFDB_DOMAIN_COMMAND,
NULL, &svc->command);
if (ret != EOK) {
DEBUG(0, ("Failed to find command from [%s] configuration\n", name));
talloc_free(svc);
return ret;
}
ret = confdb_get_int(ctx->cdb, svc, path,
CONFDB_DOMAIN_TIMEOUT,
MONITOR_DEF_PING_TIME, &svc->ping_time);
if (ret != EOK) {
DEBUG(0,("Failed to start service '%s'\n", svc->name));
talloc_free(svc);
return ret;
}
/* 'timeout = 0' should be translated to the default */
if (svc->ping_time == 0) {
svc->ping_time = MONITOR_DEF_PING_TIME;
}
talloc_free(path);
/* if no provider is present do not run the domain */
if (!svc->provider) {
talloc_free(svc);
return EIO;
}
/* if there are no custom commands, build a default one */
if (!svc->command) {
if (cmdline_debug_level == SSS_UNRESOLVED_DEBUG_LEVEL) {
svc->command = talloc_asprintf(svc,
"%s/sssd_be --domain %s%s%s",
SSSD_LIBEXEC_PATH,
svc->name,
debug_timestamps ? ""
: " --debug-timestamps=0",
debug_to_file ? " --debug-to-files" : "");
} else {
svc->command = talloc_asprintf(svc,
"%s/sssd_be --domain %s -d %d%s%s ",
SSSD_LIBEXEC_PATH,
svc->name,
cmdline_debug_level,
debug_timestamps ? ""
: " --debug-timestamps=0",
debug_to_file ? " --debug-to-files" : "");
}
if (!svc->command) {
talloc_free(svc);
return ENOMEM;
}
}
*svc_cfg = svc;
return EOK;
}
static int add_new_provider(struct mt_ctx *ctx, const char *name)
{
int ret;
struct mt_svc *svc;
ret = get_provider_config(ctx, name, &svc);
if (ret != EOK) {
DEBUG(0, ("Could not get provider configuration for [%s]\n",
name));
return ret;
}
if (strcasecmp(svc->provider, "local") == 0) {
/* The LOCAL provider requires no back-end currently
* We'll add it to the service list, but we don't need
* to poll it.
*/
svc->svc_started = true;
DLIST_ADD(ctx->svc_list, svc);
return ENOENT;
}
ret = start_service(svc);
if (ret != EOK) {
DEBUG(0,("Failed to start service '%s'\n", svc->name));
talloc_free(svc);
}
return ret;
}
static void monitor_hup(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *ctx = talloc_get_type(private_data, struct mt_ctx);
struct mt_svc *cur_svc;
DEBUG(1, ("Received SIGHUP.\n"));
/* Signal all services to rotate debug files */
for(cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
service_signal_rotate(cur_svc);
}
}
static int monitor_cleanup(void)
{
char *file;
int ret;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
file = talloc_asprintf(tmp_ctx, "%s/%s.pid", PID_PATH, "sssd");
if (file == NULL) {
return ENOMEM;
}
errno = 0;
ret = unlink(file);
if (ret == -1) {
ret = errno;
DEBUG(0, ("Error removing pidfile! (%d [%s])\n",
ret, strerror(ret)));
talloc_free(file);
return errno;
}
talloc_free(file);
return EOK;
}
static void monitor_quit(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);
struct mt_svc *svc;
pid_t pid;
int status;
errno_t error;
int kret;
bool killed;
DEBUG(8, ("Received shutdown command\n"));
DEBUG(0, ("Monitor received %s: terminating children\n",
strsignal(signum)));
/* Kill all of our known children manually */
DLIST_FOR_EACH(svc, mt_ctx->svc_list) {
if (svc->pid == 0) {
/* The local provider has no PID */
continue;
}
killed = false;
DEBUG(1, ("Terminating [%s][%d]\n", svc->name, svc->pid));
do {
errno = 0;
kret = kill(svc->pid, SIGTERM);
if (kret < 0) {
error = errno;
DEBUG(1, ("Couldn't kill [%s][%d]: [%s]\n",
svc->name, svc->pid, strerror(error)));
}
error = 0;
do {
errno = 0;
pid = waitpid(svc->pid, &status, WNOHANG);
if (pid == -1) {
/* An error occurred while waiting */
error = errno;
if (error != EINTR) {
DEBUG(0, ("[%d][%s] while waiting for [%s]\n",
error, strerror(error), svc->name));
/* Forcibly kill this child */
kill(svc->pid, SIGKILL);
break;
}
} else if (pid != 0) {
error = 0;
if WIFEXITED(status) {
DEBUG(1, ("Child [%s] exited gracefully\n", svc->name));
} else if WIFSIGNALED(status) {
DEBUG(1, ("Child [%s] terminated with a signal\n", svc->name));
} else {
DEBUG(0, ("Child [%s] did not exit cleanly\n", svc->name));
/* Forcibly kill this child */
kill(svc->pid, SIGKILL);
}
killed = true;
}
} while (error == EINTR);
if (!killed) {
/* Sleep 10ms and try again */
usleep(10000);
}
} while (!killed);
}
#if HAVE_GETPGRP
/* Kill any remaining children in our process group, just in case
* we have any leftover children we don't expect. For example, if
* a krb5_child or ldap_child is running at the same moment.
*/
error = 0;
if (getpgrp() == getpid()) {
kill(-getpgrp(), SIGTERM);
do {
errno = 0;
pid = waitpid(0, &status, 0);
if (pid == -1) {
error = errno;
}
} while (error == EINTR || pid > 0);
}
#endif
monitor_cleanup();
exit(0);
}
static void signal_offline(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *monitor;
struct mt_svc *cur_svc;
monitor = talloc_get_type(private_data, struct mt_ctx);
DEBUG(8, ("Signaling providers to go offline immediately.\n"));
/* Signal all providers to immediately go offline */
for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
/* Don't signal services, only providers */
if (cur_svc->provider) {
service_signal_offline(cur_svc);
}
}
}
static void signal_offline_reset(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
int count,
void *siginfo,
void *private_data)
{
struct mt_ctx *monitor;
struct mt_svc *cur_svc;
monitor = talloc_get_type(private_data, struct mt_ctx);
DEBUG(8, ("Signaling providers to reset offline immediately.\n"));
for(cur_svc = monitor->svc_list; cur_svc; cur_svc = cur_svc->next) {
if (cur_svc->provider) {
service_signal_reset_offline(cur_svc);
}
}
}
int read_config_file(const char *config_file)
{
int ret;
struct collection_item *sssd_config = NULL;
struct collection_item *error_list = NULL;
/* Read the configuration into a collection */
ret = config_from_file("sssd", config_file, &sssd_config,
INI_STOP_ON_ANY, &error_list);
if (ret != EOK) {
DEBUG(0, ("Parse error reading configuration file [%s]\n",
config_file));
print_file_parsing_errors(stderr, error_list);
}
free_ini_config_errors(error_list);
free_ini_config(sssd_config);
return ret;
}
static int monitor_ctx_destructor(void *mem)
{
struct mt_ctx *mon = talloc_get_type(mem, struct mt_ctx);
struct mt_svc *svc;
/* zero out references in svcs so that they don't try
* to access the monitor context on process shutdown */
for (svc = mon->svc_list; svc; svc = svc->next) {
svc->mt_ctx = NULL;
}
return 0;
}
static errno_t load_configuration(TALLOC_CTX *mem_ctx,
const char *config_file,
struct mt_ctx **monitor)
{
errno_t ret;
struct mt_ctx *ctx;
char *cdb_file = NULL;
ctx = talloc_zero(mem_ctx, struct mt_ctx);
if(!ctx) {
return ENOMEM;
}
talloc_set_destructor((TALLOC_CTX *)ctx, monitor_ctx_destructor);
cdb_file = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
if (cdb_file == NULL) {
DEBUG(0,("Out of memory, aborting!\n"));
ret = ENOMEM;
goto done;
}
ret = confdb_init(ctx, &ctx->cdb, cdb_file);
if (ret != EOK) {
DEBUG(0,("The confdb initialization failed\n"));
goto done;
}
/* Initialize the CDB from the configuration file */
ret = confdb_test(ctx->cdb);
if (ret == ENOENT) {
/* First-time setup */
/* Purge any existing confdb in case an old
* misconfiguration gets in the way
*/
talloc_zfree(ctx->cdb);
unlink(cdb_file);
ret = confdb_init(ctx, &ctx->cdb, cdb_file);
if (ret != EOK) {
DEBUG(0,("The confdb initialization failed\n"));
goto done;
}
/* Load special entries */
ret = confdb_create_base(ctx->cdb);
if (ret != EOK) {
DEBUG(0, ("Unable to load special entries into confdb\n"));
goto done;
}
} else if (ret != EOK) {
DEBUG(0, ("Fatal error initializing confdb\n"));
goto done;
}
talloc_zfree(cdb_file);
ret = confdb_init_db(config_file, ctx->cdb);
if (ret != EOK) {
DEBUG(0, ("ConfDB initialization has failed [%s]\n",
strerror(ret)));
goto done;
}
/* Validate the configuration in the database */
/* Read in the monitor's configuration */
ret = get_monitor_config(ctx);
if (ret != EOK) {
goto done;
}
*monitor = ctx;
ret = EOK;
done:
if (ret != EOK) {
talloc_free(ctx);
}
return ret;
}
#ifdef HAVE_SYS_INOTIFY_H
static void process_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr);
static void config_file_changed(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *data)
{
struct tevent_timer *te = NULL;
struct timeval tv;
struct config_file_ctx *file_ctx;
file_ctx = talloc_get_type(data, struct config_file_ctx);
if (file_ctx->needs_update) {
/* Skip updating. It's already queued for update.
*/
return;
}
/* We will queue the file for update in one second.
* This way, if there is a script writing to the file
* repeatedly, we won't be attempting to update multiple
* times.
*/
gettimeofday(&tv, NULL);
tv.tv_sec += 1;
te = tevent_add_timer(ev, ev, tv, process_config_file, file_ctx);
if (!te) {
DEBUG(0, ("Unable to queue config file update! Exiting.\n"));
kill(getpid(), SIGTERM);
return;
}
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);
static void process_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
TALLOC_CTX *tmp_ctx;
struct inotify_event *in_event;
char *buf;
char *name;
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);
DEBUG(1, ("Processing config file changes\n"));
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return;
buf = talloc_size(tmp_ctx, event_size);
if (!buf) {
goto done;
}
total_len = 0;
while (total_len < event_size) {
len = read(file_ctx->mt_ctx->inotify_fd, buf+total_len,
event_size-total_len);
if (len == -1) {
if (errno == EINTR || errno == EAGAIN) continue;
DEBUG(0, ("Critical error reading inotify file descriptor.\n"));
goto done;
}
total_len += len;
}
in_event = (struct inotify_event *)buf;
if (in_event->len > 0) {
/* Read in the name, even though we don't use it,
* so that read ptr is in the right place
*/
name = talloc_size(tmp_ctx, len);
if (!name) {
goto done;
}
total_len = 0;
while (total_len < in_event->len) {
len = read(file_ctx->mt_ctx->inotify_fd, &name, in_event->len);
if (len == -1) {
if (errno == EINTR || errno == EAGAIN) continue;
DEBUG(0, ("Critical error reading inotify file descriptor.\n"));
goto done;
}
total_len += len;
}
}
for (cb = file_ctx->callbacks; cb; cb = cb->next) {
if (cb->wd == in_event->wd) {
break;
}
}
if (!cb) {
DEBUG(0, ("Unknown watch descriptor\n"));
goto done;
}
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,
* the kernel will send us an IN_IGNORE signal.
* We will try to open a new watch descriptor on the
* new file.
*/
struct timeval tv;
struct tevent_timer *tev;
tv.tv_sec = t.tv_sec+5;
tv.tv_usec = t.tv_usec;
DEBUG(5, ("Restoring inotify watch.\n"));
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);
goto done;
}
rw_ctx->cb = cb;
rw_ctx->file_ctx = file_ctx;
tev = tevent_add_timer(ev, rw_ctx, tv, rewatch_config_file, rw_ctx);
if (tev == NULL) {
DEBUG(0, ("Could not restore inotify watch. Quitting!\n"));
close(file_ctx->mt_ctx->inotify_fd);
kill(getpid(), SIGTERM);
}
goto done;
}
/* Tell the monitor to signal the children */
cb->fn(file_ctx, cb->filename);
file_ctx->needs_update = 0;
done:
talloc_free(tmp_ctx);
}
errno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
struct mt_ctx *ctx,
const char *file,
monitor_reconf_fn fn);
static void rewatch_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
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;
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 */
cb->retries++;
if (cb->retries > 6) {
DEBUG(0, ("Could not restore inotify watch. Switching to polling!\n"));
close(file_ctx->mt_ctx->inotify_fd);
err = monitor_config_file_fallback(file_ctx->parent_ctx,
file_ctx->mt_ctx,
cb->filename,
cb->fn);
if (err != EOK)
kill(getpid(), SIGTERM);
cb->fn(file_ctx, cb->filename);
talloc_free(rw_ctx);
/* A new callback was created in monitor_config_file_fallback()*/
DLIST_REMOVE(file_ctx->callbacks, cb);
talloc_free(cb);
return;
}
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",
cb->filename, err, strerror(err)));
tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx);
if (tev == NULL) {
DEBUG(0, ("Could not restore inotify watch. Quitting!\n"));
close(file_ctx->mt_ctx->inotify_fd);
kill(getpid(), SIGTERM);
}
return;
}
cb->retries = 0;
/* Tell the monitor to signal the children */
cb->fn(file_ctx, cb->filename);
talloc_free(rw_ctx);
file_ctx->needs_update = 0;
}
#endif
static void poll_config_file(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
int ret, err;
struct stat file_stat;
struct timeval tv;
struct config_file_ctx *file_ctx;
struct config_file_callback *cb;
file_ctx = talloc_get_type(ptr,struct config_file_ctx);
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 */
cb->fn(file_ctx, cb->filename);
}
}
gettimeofday(&tv, NULL);
tv.tv_sec += CONFIG_FILE_POLL_INTERVAL;
tv.tv_usec = 0;
file_ctx->timer = tevent_add_timer(ev, file_ctx->parent_ctx, tv,
poll_config_file, file_ctx);
if (!file_ctx->timer) {
DEBUG(0, ("Error: Config file no longer monitored for changes!\n"));
}
}
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;
}
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 |= 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;
}
}
cb = talloc_zero(file_ctx, struct config_file_callback);
if(!cb) {
close(file_ctx->mt_ctx->inotify_fd);
return EIO;
}
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",
cb->filename, err, strerror(err)));
close(file_ctx->mt_ctx->inotify_fd);
return err;
}
cb->fn = fn;
DLIST_ADD(file_ctx->callbacks, cb);
return EOK;
#else
return EINVAL;
#endif
}
static int monitor_config_file(TALLOC_CTX *mem_ctx,
struct mt_ctx *ctx,
const char *file,
monitor_reconf_fn fn)
{
int ret, err;
bool use_inotify;
struct stat file_stat;
ret = stat(file, &file_stat);
if (ret < 0) {
err = errno;
DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n",
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;
ctx->file_ctx->parent_ctx = mem_ctx;
ctx->file_ctx->mt_ctx = ctx;
}
ret = confdb_get_bool(ctx->cdb, ctx,
CONFDB_MONITOR_CONF_ENTRY,
CONFDB_MONITOR_TRY_INOTIFY,
true, &use_inotify);
if (ret != EOK) {
talloc_free(ctx->file_ctx);
return ret;
}
if (use_inotify) {
ret = try_inotify(ctx->file_ctx, file, fn);
if (ret != EOK) {
use_inotify = false;
}
}
if (!use_inotify) {
/* Could not monitor file with inotify, fall back to polling */
ret = monitor_config_file_fallback(mem_ctx, ctx, file, fn);
}
return ret;
}
errno_t monitor_config_file_fallback(TALLOC_CTX *mem_ctx,
struct mt_ctx *ctx,
const char *file,
monitor_reconf_fn fn)
{
struct config_file_callback *cb = NULL;
struct stat file_stat;
int ret, err;
struct timeval tv;
ret = stat(file, &file_stat);
if (ret < 0) {
err = errno;
DEBUG(0, ("Could not stat file [%s]. Error [%d:%s]\n",
file, err, strerror(err)));
return err;
}
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;
}
}
return EOK;
}
int monitor_process_init(struct mt_ctx *ctx,
const char *config_file)
{
TALLOC_CTX *tmp_ctx;
struct sysdb_ctx_list *db_list;
struct tevent_signal *tes;
struct sss_domain_info *dom;
int num_providers;
int ret;
/* Set up an event handler for a SIGHUP */
tes = tevent_add_signal(ctx->ev, ctx, SIGHUP, 0,
monitor_hup, ctx);
if (tes == NULL) {
return EIO;
}
/* Set up an event handler for a SIGINT */
BlockSignals(false, SIGINT);
tes = tevent_add_signal(ctx->ev, ctx, SIGINT, 0,
monitor_quit, ctx);
if (tes == NULL) {
return EIO;
}
/* Set up an event handler for a SIGTERM */
tes = tevent_add_signal(ctx->ev, ctx, SIGTERM, 0,
monitor_quit, ctx);
if (tes == NULL) {
return EIO;
}
/* Handle SIGUSR1 (tell all providers to go offline) */
BlockSignals(false, SIGUSR1);
tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
signal_offline, ctx);
if (tes == NULL) {
return EIO;
}
/* Handle SIGUSR2 (tell all providers to go reset offline) */
BlockSignals(false, SIGUSR2);
tes = tevent_add_signal(ctx->ev, ctx, SIGUSR2, 0,
signal_offline_reset, ctx);
if (tes == NULL) {
return EIO;
}
#if 0
This feature is incomplete and can leave the SSSD in a bad state if the
config file is changed while the SSSD is running.
Uncomment this once the backends are honoring reloadConfig()
/* Watch for changes to the confdb config file */
ret = monitor_config_file(ctx, ctx, config_file, monitor_signal_reconf);
if (ret != EOK) {
return ret;
}
#endif
/* Watch for changes to the DNS resolv.conf */
ret = monitor_config_file(ctx, ctx, RESOLV_CONF_PATH,
monitor_update_resolv);
if (ret != EOK) {
return ret;
}
/* Avoid a startup race condition between process.
* We need to handle DB upgrades or DB creation only
* in one process before all other start.
*/
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return ENOMEM;
}
ret = sysdb_init(tmp_ctx, ctx->cdb, NULL, true, &db_list);
if (ret != EOK) {
return ret;
}
talloc_zfree(tmp_ctx);
/* Initialize D-BUS Server
* The monitor will act as a D-BUS server for all
* SSSD processes */
ret = monitor_dbus_init(ctx);
if (ret != EOK) {
return ret;
}
ret = setup_netlink(ctx, ctx->ev, network_status_change_cb,
ctx, &ctx->nlctx);
if (ret != EOK) {
DEBUG(2, ("Cannot set up listening for network notifications\n"));
return ret;
}
/* start providers */
num_providers = 0;
for (dom = ctx->domains; dom; dom = dom->next) {
ret = add_new_provider(ctx, dom->name);
if (ret != EOK && ret != ENOENT) {
return ret;
}
if (ret != ENOENT) {
num_providers++;
}
}
if (num_providers > 0) {
/* now set the services stratup timeout *
* (responders will be started automatically when all
* providers are up and running or when the tomeout
* expires) */
ret = add_services_startup_timeout(ctx);
if (ret != EOK) {
return ret;
}
} else {
int i;
ctx->services_started = true;
/* No providers start services immediately
* Normally this means only LOCAL is configured */
for (i = 0; ctx->services[i]; i++) {
add_new_service(ctx, ctx->services[i]);
}
}
/* now start checking for global events */
set_global_checker(ctx);
return EOK;
}
static void init_timeout(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
struct mon_init_conn *mini;
DEBUG(2, ("Client timed out before Identification!\n"));
mini = talloc_get_type(ptr, struct mon_init_conn);
sbus_disconnect(mini->conn);
talloc_zfree(mini);
}
/*
* monitor_service_init
* Set up a timeout function and temporary connection structure.
* If the client does not identify before the timeout kicks in,
* the client is forcibly disconnected.
*/
static int monitor_service_init(struct sbus_connection *conn, void *data)
{
struct mt_ctx *ctx;
struct mon_init_conn *mini;
struct timeval tv;
DEBUG(3, ("Initializing D-BUS Service\n"));
ctx = talloc_get_type(data, struct mt_ctx);
mini = talloc(conn, struct mon_init_conn);
if (!mini) {
DEBUG(0,("Out of memory?!\n"));
talloc_zfree(conn);
return ENOMEM;
}
mini->ctx = ctx;
mini->conn = conn;
/* 5 seconds should be plenty */
tv = tevent_timeval_current_ofs(10, 0);
mini->timeout = tevent_add_timer(ctx->ev, mini, tv, init_timeout, mini);
if (!mini->timeout) {
DEBUG(0,("Out of memory?!\n"));
talloc_zfree(conn);
return ENOMEM;
}
sbus_conn_set_private_data(conn, mini);
return EOK;
}
/* service_send_ping
* this function send a dbus ping to a service.
* It returns EOK if all is fine or ENXIO if the connection is
* not available (either not yet set up or teared down).
* Returns e generic error in other cases.
*/
static int service_send_ping(struct mt_svc *svc)
{
DBusMessage *msg;
int ret;
if (!svc->conn) {
DEBUG(8, ("Service not yet initialized\n"));
return ENXIO;
}
DEBUG(4,("Pinging %s\n", svc->name));
/*
* Set up identity request
* This should be a well-known path and method
* for all services
*/
msg = dbus_message_new_method_call(NULL,
MONITOR_PATH,
MONITOR_INTERFACE,
MON_CLI_METHOD_PING);
if (!msg) {
DEBUG(0,("Out of memory?!\n"));
talloc_zfree(svc->conn);
return ENOMEM;
}
ret = sbus_conn_send(svc->conn, msg,
svc->mt_ctx->service_id_timeout,
ping_check, svc, NULL);
dbus_message_unref(msg);
return ret;
}
static void ping_check(DBusPendingCall *pending, void *data)
{
struct mt_svc *svc;
DBusMessage *reply;
const char *dbus_error_name;
int type;
svc = talloc_get_type(data, struct mt_svc);
reply = dbus_pending_call_steal_reply(pending);
if (!reply) {
/* reply should never be null. This function shouldn't be called
* until reply is valid or timeout has occurred. If reply is NULL
* here, something is seriously wrong and we should bail out.
*/
DEBUG(0, ("A reply callback was called but no reply was received"
" and no timeout occurred\n"));
/* Destroy this connection */
sbus_disconnect(svc->conn);
goto done;
}
type = dbus_message_get_type(reply);
switch (type) {
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
/* ok peer replied,
* make sure we reset the failure counter in the service structure */
DEBUG(4,("Service %s replied to ping\n", svc->name));
svc->failed_pongs = 0;
break;
case DBUS_MESSAGE_TYPE_ERROR:
dbus_error_name = dbus_message_get_error_name(reply);
/* timeouts are handled in the main service check function */
if (strcmp(dbus_error_name, DBUS_ERROR_TIMEOUT) == 0)
break;
DEBUG(0,("A service PING returned an error [%s], closing connection.\n",
dbus_error_name));
/* Falling through to default intentionally*/
default:
/*
* Timeout or other error occurred or something
* unexpected happened.
* It doesn't matter which, because either way we
* know that this connection isn't trustworthy.
* We'll destroy it now.
*/
sbus_disconnect(svc->conn);
}
done:
dbus_pending_call_unref(pending);
dbus_message_unref(reply);
}
/* service_check_alive
* This function checks if the service child is still alive
*/
static int service_check_alive(struct mt_svc *svc)
{
int status;
pid_t pid;
DEBUG(4,("Checking service %s(%d) is still alive\n", svc->name, svc->pid));
pid = waitpid(svc->pid, &status, WNOHANG);
if (pid == 0) {
return EOK;
}
if (pid != svc->pid) {
DEBUG(1, ("bad return (%d) from waitpid() waiting for %d\n",
pid, svc->pid));
/* TODO: what do we do now ? */
return EINVAL;
}
if (WIFEXITED(status)) { /* children exited on it's own */
/* TODO: check configuration to see if it was removed
* from the list of process to run */
DEBUG(0,("Process [%s] exited\n", svc->name));
}
return ECHILD;
}
static void service_startup_handler(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr);
static int start_service(struct mt_svc *svc)
{
struct tevent_timer *te;
struct timeval tv;
DEBUG(4,("Queueing service %s for startup\n", svc->name));
/* at startup we need to start the data providers before the responders
* to avoid races where a service starts before sbus pipes are ready
* to accept connections. So if startup is true delay by 2 seconds any
* process that is not a data provider */
tv = tevent_timeval_current();
/* Add a timed event to start up the service.
* We have to do this in order to avoid a race
* condition where the service being started forks
* and attempts to connect to the SBUS before
* the monitor is serving it.
*/
te = tevent_add_timer(svc->mt_ctx->ev, svc, tv,
service_startup_handler, svc);
if (te == NULL) {
DEBUG(0, ("Unable to queue service %s for startup\n", svc->name));
return ENOMEM;
}
return EOK;
}
static void service_startup_handler(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t, void *ptr)
{
struct mt_svc *mt_svc;
char **args;
mt_svc = talloc_get_type(ptr, struct mt_svc);
if (mt_svc == NULL) {
return;
}
mt_svc->pid = fork();
if (mt_svc->pid != 0) {
if (mt_svc->pid == -1) {
DEBUG(0, ("Could not fork child to start service [%s]. Continuing.\n", mt_svc->name))
return;
}
/* Parent */
mt_svc->mt_ctx->check_children = true;
mt_svc->failed_pongs = 0;
DLIST_ADD(mt_svc->mt_ctx->svc_list, mt_svc);
set_tasks_checker(mt_svc);
return;
}
/* child */
args = parse_args(mt_svc->command);
execvp(args[0], args);
/* If we are here, exec() has failed
* Print errno and abort quickly */
DEBUG(0,("Could not exec %s, reason: %s\n", mt_svc->command, strerror(errno)));
/* We have to call _exit() instead of exit() here
* because a bug in D-BUS will cause the server to
* close its socket at exit() */
_exit(1);
}
int main(int argc, const char *argv[])
{
int opt;
poptContext pc;
int opt_daemon = 0;
int opt_interactive = 0;
char *opt_config_file = NULL;
char *config_file = NULL;
int flags = 0;
struct main_context *main_ctx;
TALLOC_CTX *tmp_ctx;
struct mt_ctx *monitor;
int ret;
uid_t uid;
struct poptOption long_options[] = {
POPT_AUTOHELP
SSSD_MAIN_OPTS
{"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \
_("Become a daemon (default)"), NULL }, \
{"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \
_("Run interactive (not a daemon)"), NULL}, \
{"config", 'c', POPT_ARG_STRING, &opt_config_file, 0, \
_("Specify a non-default config file"), NULL}, \
POPT_TABLEEND
};
pc = poptGetContext(argv[0], argc, argv, long_options, 0);
while((opt = poptGetNextOpt(pc)) != -1) {
switch(opt) {
default:
fprintf(stderr, "\nInvalid option %s: %s\n\n",
poptBadOption(pc, 0), poptStrerror(opt));
poptPrintUsage(pc, stderr, 0);
return 1;
}
}
/* If the level was passed at the command-line, we want
* to save it and pass it to the children later.
*/
cmdline_debug_level = debug_level;
if (opt_daemon && opt_interactive) {
fprintf(stderr, "Option -i|--interactive is not allowed together with -D|--daemon\n");
poptPrintUsage(pc, stderr, 0);
return 1;
}
if (!opt_daemon && !opt_interactive) {
opt_daemon = 1;
}
poptFreeContext(pc);
uid = getuid();
if (uid != 0) {
DEBUG(1, ("Running under %d, must be root\n", uid));
sss_log(SSS_LOG_ALERT, "sssd must be run as root");
return 8;
}
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
return 7;
}
if (opt_daemon) flags |= FLAGS_DAEMON;
if (opt_interactive) flags |= FLAGS_INTERACTIVE;
if (opt_config_file)
config_file = talloc_strdup(tmp_ctx, opt_config_file);
else
config_file = talloc_strdup(tmp_ctx, CONFDB_DEFAULT_CONFIG_FILE);
if(!config_file)
return 6;
/* we want a pid file check */
flags |= FLAGS_PID_FILE;
/* Open before server_setup() does to have logging
* during configuration checking */
if (debug_to_file) {
ret = open_debug_file();
if (ret) {
return 7;
}
}
/* Warn if nscd seems to be running */
ret = check_file(NSCD_SOCKET_PATH, -1, -1, -1, CHECK_SOCK, NULL);
if (ret == EOK) {
sss_log(SSS_LOG_NOTICE,
"nscd socket was detected. Nscd caching capabilities "
"may conflict with SSSD for users and groups. It is "
"recommended not to run nscd in parallel with SSSD, unless "
"nscd is configured not to cache the passwd, group and "
"netgroup nsswitch maps.");
}
/* Parse config file, fail if cannot be done */
ret = load_configuration(tmp_ctx, config_file, &monitor);
if (ret != EOK) {
if (ret == EPERM) {
DEBUG(1, ("Cannot read configuration file %s\n", config_file));
sss_log(SSS_LOG_ALERT,
"Cannot read config file %s, please check if permissions "
"are 0600 and the file is owned by root.root", config_file);
} else {
DEBUG(1, ("Error loading configuration database: [%d]: %s",
ret, strerror(ret)));
sss_log(SSS_LOG_ALERT, "Cannot load configuration database");
}
return 4;
}
/* set up things like debug , signals, daemonization, etc... */
monitor->conf_path = CONFDB_MONITOR_CONF_ENTRY;
ret = server_setup("sssd", flags, monitor->conf_path, &main_ctx);
if (ret != EOK) return 2;
monitor->ev = main_ctx->event_ctx;
talloc_steal(main_ctx, monitor);
ret = monitor_process_init(monitor,
config_file);
if (ret != EOK) return 3;
talloc_free(tmp_ctx);
/* loop on main */
server_loop(main_ctx);
ret = monitor_cleanup();
if (ret != EOK) return 5;
return 0;
}