From 71f15a9cee96c135f287822f503f683a8f5628b8 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 26 Jan 2010 09:37:32 -0500
Subject: [PATCH] Force offline operation with SIGUSR1

If the monitor receives SIGUSR1, it will instruct all providers to
enter offline operation. If any individual provider receives
SIGUSR1, it alone will enter offline operation.
---
 server/monitor/monitor.c            |   36 +++++++++++++++++++++++++++++++++++
 server/monitor/monitor_interfaces.h |    1 +
 server/providers/data_provider_be.c |   32 +++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/server/monitor/monitor.c b/server/monitor/monitor.c
index b3174bd..85f69c1 100644
--- a/server/monitor/monitor.c
+++ b/server/monitor/monitor.c
@@ -858,6 +858,10 @@ 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 check_domain_ranges(struct sss_domain_info *domains)
 {
@@ -1489,6 +1493,7 @@ static void monitor_quit(struct tevent_context *ev,
                          void *siginfo,
                          void *private_data)
 {
+    DEBUG(8, ("Received shutdown command\n"));
     monitor_cleanup();
 
 #if HAVE_GETPGRP
@@ -1501,6 +1506,29 @@ static void monitor_quit(struct tevent_context *ev,
     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);
+        }
+    }
+}
+
 int read_config_file(const char *config_file)
 {
     int ret;
@@ -2098,6 +2126,14 @@ int monitor_process_init(struct mt_ctx *ctx,
         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;
+    }
+
     return EOK;
 }
 
diff --git a/server/monitor/monitor_interfaces.h b/server/monitor/monitor_interfaces.h
index 1835718..c6361fa 100644
--- a/server/monitor/monitor_interfaces.h
+++ b/server/monitor/monitor_interfaces.h
@@ -41,6 +41,7 @@
 #define MON_CLI_METHOD_RELOAD "reloadConfig"
 #define MON_CLI_METHOD_SHUTDOWN "shutDown"
 #define MON_CLI_METHOD_RES_INIT "resInit"
+#define MON_CLI_METHOD_OFFLINE "goOffline" /* Applicable only to providers */
 
 #define SSSD_SERVICE_PIPE "private/sbus-monitor"
 
diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c
index 97cc9f8..abec3b9 100644
--- a/server/providers/data_provider_be.c
+++ b/server/providers/data_provider_be.c
@@ -53,10 +53,13 @@
 
 static int data_provider_res_init(DBusMessage *message,
                                   struct sbus_connection *conn);
+static int data_provider_go_offline(DBusMessage *message,
+                                    struct sbus_connection *conn);
 
 struct sbus_method monitor_be_methods[] = {
     { MON_CLI_METHOD_PING, monitor_common_pong },
     { MON_CLI_METHOD_RES_INIT, data_provider_res_init },
+    { MON_CLI_METHOD_OFFLINE, data_provider_go_offline },
     { NULL, NULL }
 };
 
@@ -1018,12 +1021,24 @@ done:
     return ret;
 }
 
+static void signal_be_offline(struct tevent_context *ev,
+                              struct tevent_signal *se,
+                              int signum,
+                              int count,
+                              void *siginfo,
+                              void *private_data)
+{
+    struct be_ctx *ctx = talloc_get_type(private_data, struct be_ctx);
+    be_mark_offline(ctx);
+}
+
 int be_process_init(TALLOC_CTX *mem_ctx,
                     const char *be_domain,
                     struct tevent_context *ev,
                     struct confdb_ctx *cdb)
 {
     struct be_ctx *ctx;
+    struct tevent_signal *tes;
     int ret;
 
     ctx = talloc_zero(mem_ctx, struct be_ctx);
@@ -1118,6 +1133,14 @@ int be_process_init(TALLOC_CTX *mem_ctx,
                   "from provider [%s].\n", ctx->bet_info[BET_CHPASS].mod_name));
     }
 
+    /* Handle SIGUSR1 to force offline behavior */
+    BlockSignals(false, SIGUSR1);
+    tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
+                            signal_be_offline, ctx);
+    if (tes == NULL) {
+        return EIO;
+    }
+
     return EOK;
 }
 
@@ -1205,3 +1228,12 @@ static int data_provider_res_init(DBusMessage *message,
 
     return monitor_common_res_init(message, conn);
 }
+
+static int data_provider_go_offline(DBusMessage *message,
+                                    struct sbus_connection *conn)
+{
+    struct be_ctx *be_ctx;
+    be_ctx = talloc_get_type(sbus_conn_get_private_data(conn), struct be_ctx);
+    be_mark_offline(be_ctx);
+    return monitor_common_pong(message, conn);
+}
-- 
1.6.6

