summaryrefslogtreecommitdiff
path: root/src/nm-dispatcher/nm-dispatcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-dispatcher/nm-dispatcher.c')
-rw-r--r--src/nm-dispatcher/nm-dispatcher.c216
1 files changed, 127 insertions, 89 deletions
diff --git a/src/nm-dispatcher/nm-dispatcher.c b/src/nm-dispatcher/nm-dispatcher.c
index b96cc82ea9..b175d8eed3 100644
--- a/src/nm-dispatcher/nm-dispatcher.c
+++ b/src/nm-dispatcher/nm-dispatcher.c
@@ -7,15 +7,15 @@
#include "libnm-client-aux-extern/nm-default-client.h"
-#include <syslog.h>
+#include <arpa/inet.h>
+#include <signal.h>
#include <stdio.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <sys/types.h>
-#include <signal.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
-#include <arpa/inet.h>
+#include <syslog.h>
+#include <unistd.h>
#include "libnm-core-aux-extern/nm-dispatcher-api.h"
#include "libnm-glib-aux/nm-dbus-aux.h"
@@ -33,29 +33,36 @@
typedef struct Request Request;
-static struct {
+typedef struct {
GDBusConnection *dbus_connection;
GCancellable * quit_cancellable;
- bool log_verbose;
- bool log_stdout;
- gboolean persist;
- GSource * quit_source;
- guint request_id_counter;
- guint dbus_regist_id;
+
+ bool log_verbose;
+ bool log_stdout;
+
+ GSource *source_idle_timeout;
gint64 start_timestamp_msec;
- bool name_requested;
+ guint request_id_counter;
+ guint service_regist_id;
+
+ gboolean persist;
+
+ Request *current_request;
+ GQueue * requests_waiting;
+ int num_requests_pending;
bool exit_with_failure;
+ bool name_requested;
+ bool reject_new_requests;
+
bool shutdown_timeout;
bool shutdown_quitting;
+} GlobalData;
- Request *current_request;
- GQueue * requests_waiting;
- int num_requests_pending;
-} gl;
+GlobalData gl;
typedef struct {
Request *request;
@@ -204,18 +211,20 @@ request_free(Request *request)
g_slice_free(Request, request);
}
+/*****************************************************************************/
+
static gboolean
-quit_timeout_cb(gpointer user_data)
+_idle_timeout_cb(gpointer user_data)
{
- nm_clear_g_source_inst(&gl.quit_source);
+ nm_clear_g_source_inst(&gl.source_idle_timeout);
gl.shutdown_timeout = TRUE;
return G_SOURCE_CONTINUE;
}
static void
-quit_timeout_reschedule(void)
+_idle_timeout_restart(void)
{
- nm_clear_g_source_inst(&gl.quit_source);
+ nm_clear_g_source_inst(&gl.source_idle_timeout);
if (gl.persist)
return;
@@ -226,9 +235,11 @@ quit_timeout_reschedule(void)
if (gl.num_requests_pending > 0)
return;
- gl.quit_source = nm_g_timeout_add_source(10000, quit_timeout_cb, NULL);
+ gl.source_idle_timeout = nm_g_timeout_add_source(10000, _idle_timeout_cb, NULL);
}
+/*****************************************************************************/
+
/**
* next_request:
*
@@ -276,7 +287,7 @@ next_request(Request *request)
* Checks if all the scripts for the request have terminated and in such case
* it sends the D-Bus response and releases the request resources.
*
- * It also decreases @num_requests_pending and possibly does quit_timeout_reschedule().
+ * It also decreases @num_requests_pending and possibly does _idle_timeout_restart().
*/
static void
complete_request(Request *request)
@@ -315,7 +326,7 @@ complete_request(Request *request)
nm_assert(gl.num_requests_pending > 0);
if (--gl.num_requests_pending <= 0) {
nm_assert(!gl.current_request && !g_queue_peek_head(gl.requests_waiting));
- quit_timeout_reschedule();
+ _idle_timeout_restart();
}
}
@@ -693,7 +704,7 @@ script_must_wait(const char *path)
}
static void
-_method_call_action(GDBusMethodInvocation *invocation, GVariant *parameters)
+_handle_action(GDBusMethodInvocation *invocation, GVariant *parameters)
{
const char * action;
gs_unref_variant GVariant *connection = NULL;
@@ -811,7 +822,7 @@ _method_call_action(GDBusMethodInvocation *invocation, GVariant *parameters)
gl.num_requests_pending++;
gl.shutdown_timeout = FALSE;
- nm_clear_g_source_inst(&gl.quit_source);
+ nm_clear_g_source_inst(&gl.source_idle_timeout);
for (i = 0; i < request->scripts->len; i++) {
ScriptInfo *s = g_ptr_array_index(request->scripts, i);
@@ -857,7 +868,7 @@ _method_call_action(GDBusMethodInvocation *invocation, GVariant *parameters)
}
static void
-_method_call_ping(GDBusMethodInvocation *invocation, GVariant *parameters)
+_handle_ping(GDBusMethodInvocation *invocation, GVariant *parameters)
{
gs_free char *msg = NULL;
gint64 running_msec;
@@ -877,22 +888,29 @@ _method_call_ping(GDBusMethodInvocation *invocation, GVariant *parameters)
}
static void
-_method_call(GDBusConnection * connection,
- const char * sender,
- const char * object_path,
- const char * interface_name,
- const char * method_name,
- GVariant * parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
+_bus_method_call(GDBusConnection * connection,
+ const char * sender,
+ const char * object_path,
+ const char * interface_name,
+ const char * method_name,
+ GVariant * parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
{
+ if (gl.reject_new_requests) {
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NO_SERVER,
+ "Server is exiting");
+ return;
+ }
if (nm_streq(interface_name, NM_DISPATCHER_DBUS_INTERFACE)) {
if (nm_streq(method_name, "Action")) {
- _method_call_action(invocation, parameters);
+ _handle_action(invocation, parameters);
return;
}
if (nm_streq(method_name, "Ping")) {
- _method_call_ping(invocation, parameters);
+ _handle_ping(invocation, parameters);
return;
}
}
@@ -935,7 +953,7 @@ static gboolean
_bus_register_service(void)
{
static const GDBusInterfaceVTable interface_vtable = {
- .method_call = _method_call,
+ .method_call = _bus_method_call,
};
gs_free_error GError * error = NULL;
NMDBusConnectionCallBlockingData data = {
@@ -944,7 +962,7 @@ _bus_register_service(void)
gs_unref_variant GVariant *ret = NULL;
guint32 ret_val;
- gl.dbus_regist_id =
+ gl.service_regist_id =
g_dbus_connection_register_object(gl.dbus_connection,
NM_DISPATCHER_DBUS_PATH,
interface_info,
@@ -952,7 +970,7 @@ _bus_register_service(void)
NULL,
NULL,
&error);
- if (gl.dbus_regist_id == 0) {
+ if (gl.service_regist_id == 0) {
_LOG_X_W("dbus: could not export dispatcher D-Bus interface %s: %s",
NM_DISPATCHER_DBUS_PATH,
error->message);
@@ -1050,7 +1068,7 @@ logging_shutdown(void)
}
static gboolean
-signal_handler(gpointer user_data)
+_signal_callback_term(gpointer user_data)
{
if (!gl.shutdown_quitting) {
gl.shutdown_quitting = TRUE;
@@ -1060,16 +1078,62 @@ signal_handler(gpointer user_data)
return G_SOURCE_CONTINUE;
}
+/*****************************************************************************/
+
static void
_bus_release_name_cb(GObject *source, GAsyncResult *result, gpointer user_data)
{
nm_assert(gl.num_requests_pending > 0);
+ gl.reject_new_requests = TRUE;
gl.num_requests_pending--;
g_main_context_wakeup(NULL);
}
static gboolean
-parse_command_line(int *p_argc, char ***p_argv, GError **error)
+_bus_release_name(void)
+{
+ int r;
+
+ /* We already requested a name. To exit-on-idle without race, we need to dance.
+ * See https://lists.freedesktop.org/archives/dbus/2015-May/016671.html . */
+
+ if (!gl.name_requested)
+ return FALSE;
+
+ gl.name_requested = FALSE;
+ gl.shutdown_quitting = TRUE;
+
+ _LOG_X_T("shutdown: release-name");
+
+ /* we create a fake pending request. */
+ gl.num_requests_pending++;
+ nm_clear_g_source_inst(&gl.source_idle_timeout);
+
+ r = nm_sd_notify("STOPPING=1");
+ if (r < 0)
+ _LOG_X_W("shutdown: sd_notifiy(STOPPING=1) failed: %s", nm_strerror_native(-r));
+ else
+ _LOG_X_T("shutdown: sd_notifiy(STOPPING=1) succeeded");
+
+ g_dbus_connection_call(gl.dbus_connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "ReleaseName",
+ g_variant_new("(s)", NM_DISPATCHER_DBUS_SERVICE),
+ G_VARIANT_TYPE("(u)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 10000,
+ NULL,
+ _bus_release_name_cb,
+ NULL);
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+_initial_setup(int *p_argc, char ***p_argv, GError **error)
{
GOptionContext *opt_ctx;
gboolean arg_debug = FALSE;
@@ -1115,6 +1179,8 @@ parse_command_line(int *p_argc, char ***p_argv, GError **error)
return success;
}
+/*****************************************************************************/
+
int
main(int argc, char **argv)
{
@@ -1123,14 +1189,16 @@ main(int argc, char **argv)
GSource * source_int = NULL;
signal(SIGPIPE, SIG_IGN);
- source_term = nm_g_unix_signal_add_source(SIGTERM, signal_handler, GINT_TO_POINTER(SIGTERM));
- source_int = nm_g_unix_signal_add_source(SIGINT, signal_handler, GINT_TO_POINTER(SIGINT));
+ source_term =
+ nm_g_unix_signal_add_source(SIGTERM, _signal_callback_term, GINT_TO_POINTER(SIGTERM));
+ source_int =
+ nm_g_unix_signal_add_source(SIGINT, _signal_callback_term, GINT_TO_POINTER(SIGINT));
gl.start_timestamp_msec = nm_utils_clock_gettime_msec(CLOCK_BOOTTIME);
gl.quit_cancellable = g_cancellable_new();
- if (!parse_command_line(&argc, &argv, &error)) {
+ if (!_initial_setup(&argc, &argv, &error)) {
_LOG_X_W("Error parsing command line arguments: %s", error->message);
gl.exit_with_failure = TRUE;
goto done;
@@ -1164,7 +1232,7 @@ main(int argc, char **argv)
gl.requests_waiting = g_queue_new();
- quit_timeout_reschedule();
+ _idle_timeout_restart();
if (!_bus_register_service()) {
/* we failed to start the D-Bus service, and will shut down. However,
@@ -1173,68 +1241,39 @@ main(int argc, char **argv)
if (!g_cancellable_is_cancelled(gl.quit_cancellable))
gl.exit_with_failure = TRUE;
gl.shutdown_quitting = TRUE;
+
+ if (!gl.name_requested)
+ gl.reject_new_requests = TRUE;
}
while (TRUE) {
+ if (gl.shutdown_quitting)
+ _bus_release_name();
+
if (gl.num_requests_pending > 0) {
/* while we have requests pending, we cannot stop processing them... */
} else if (gl.shutdown_timeout || gl.shutdown_quitting) {
- if (gl.name_requested) {
- int r;
-
- /* We already requested a name. To exit-on-idle without race, we need to dance.
- * See https://lists.freedesktop.org/archives/dbus/2015-May/016671.html . */
-
- gl.name_requested = FALSE;
- gl.shutdown_quitting = TRUE;
-
- _LOG_X_T("shutdown: release-name");
-
- /* we create a fake pending request. */
- gl.num_requests_pending++;
- nm_clear_g_source_inst(&gl.quit_source);
-
- r = nm_sd_notify("STOPPING=1");
- if (r < 0)
- _LOG_X_W("shutdown: sd_notifiy(STOPPING=1) failed: %s", nm_strerror_native(-r));
- else
- _LOG_X_T("shutdown: sd_notifiy(STOPPING=1) succeeded");
-
- g_dbus_connection_call(gl.dbus_connection,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "ReleaseName",
- g_variant_new("(s)", NM_DISPATCHER_DBUS_SERVICE),
- G_VARIANT_TYPE("(u)"),
- G_DBUS_CALL_FLAGS_NONE,
- 10000,
- NULL,
- _bus_release_name_cb,
- NULL);
- continue;
- }
-
- break;
+ if (!_bus_release_name())
+ break;
}
g_main_context_iteration(NULL, TRUE);
}
done:
- nm_g_main_context_iterate_ready(NULL);
-
gl.shutdown_quitting = TRUE;
g_cancellable_cancel(gl.quit_cancellable);
nm_assert(gl.num_requests_pending == 0);
- if (gl.dbus_regist_id != 0)
- g_dbus_connection_unregister_object(gl.dbus_connection, nm_steal_int(&gl.dbus_regist_id));
+ if (gl.service_regist_id != 0) {
+ g_dbus_connection_unregister_object(gl.dbus_connection,
+ nm_steal_int(&gl.service_regist_id));
+ }
nm_clear_pointer(&gl.requests_waiting, g_queue_free);
- nm_clear_g_source_inst(&gl.quit_source);
+ nm_clear_g_source_inst(&gl.source_idle_timeout);
if (gl.dbus_connection) {
g_dbus_connection_flush_sync(gl.dbus_connection, NULL, NULL);
@@ -1250,7 +1289,6 @@ done:
nm_clear_g_source_inst(&source_term);
nm_clear_g_source_inst(&source_int);
-
g_clear_object(&gl.quit_cancellable);
return gl.exit_with_failure ? 1 : 0;