diff options
| author | Michael Biebl <biebl@debian.org> | 2020-10-05 22:27:18 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-10-05 22:27:18 +0200 |
| commit | aafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e (patch) | |
| tree | a2a9bb4d007339a0b1304540388230ccedac32bd /dispatcher/nm-dispatcher.c | |
| parent | e7b44ef4c80907346ec7492a09c45277459924fc (diff) | |
New upstream version 1.27.90 upstream/1.27.90
Diffstat (limited to 'dispatcher/nm-dispatcher.c')
| -rw-r--r-- | dispatcher/nm-dispatcher.c | 1768 |
1 files changed, 883 insertions, 885 deletions
diff --git a/dispatcher/nm-dispatcher.c b/dispatcher/nm-dispatcher.c index e1737d85..e14cc40b 100644 --- a/dispatcher/nm-dispatcher.c +++ b/dispatcher/nm-dispatcher.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2008 - 2012 Red Hat, Inc. */ @@ -24,172 +24,182 @@ typedef struct Request Request; static struct { - GDBusConnection *dbus_connection; - GMainLoop *loop; - gboolean debug; - gboolean persist; - guint quit_id; - guint request_id_counter; - gboolean ever_acquired_name; - bool exit_with_failure; - - Request *current_request; - GQueue *requests_waiting; - int num_requests_pending; + GDBusConnection *dbus_connection; + GMainLoop * loop; + gboolean debug; + gboolean persist; + guint quit_id; + guint request_id_counter; + gboolean ever_acquired_name; + bool exit_with_failure; + + Request *current_request; + GQueue * requests_waiting; + int num_requests_pending; } gl; typedef struct { - Request *request; - - char *script; - GPid pid; - DispatchResult result; - char *error; - gboolean wait; - gboolean dispatched; - guint watch_id; - guint timeout_id; + Request *request; + + char * script; + GPid pid; + DispatchResult result; + char * error; + gboolean wait; + gboolean dispatched; + guint watch_id; + guint timeout_id; } ScriptInfo; struct Request { - guint request_id; - - GDBusMethodInvocation *context; - char *action; - char *iface; - char **envp; - gboolean debug; - - GPtrArray *scripts; /* list of ScriptInfo */ - guint idx; - int num_scripts_done; - int num_scripts_nowait; + guint request_id; + + GDBusMethodInvocation *context; + char * action; + char * iface; + char ** envp; + gboolean debug; + + GPtrArray *scripts; /* list of ScriptInfo */ + guint idx; + int num_scripts_done; + int num_scripts_nowait; }; /*****************************************************************************/ -#define __LOG_print(print_cmd, ...) \ - G_STMT_START { \ - if (FALSE) { \ - /* g_message() alone does not warn about invalid format. Add a dummy printf() statement to - * get a compiler warning about wrong format. */ \ - printf (__VA_ARGS__); \ - } \ - print_cmd (__VA_ARGS__); \ - } G_STMT_END - -#define __LOG_print_R(print_cmd, _request, ...) \ - G_STMT_START { \ - __LOG_print (print_cmd, \ - "req:%u '%s'%s%s%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - (_request)->request_id, \ - (_request)->action, \ - (_request)->iface ? " [" : "", \ - (_request)->iface ?: "", \ - (_request)->iface ? "]" : "" \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } G_STMT_END - -#define __LOG_print_S(print_cmd, _request, _script, ...) \ - G_STMT_START { \ - __LOG_print_R (print_cmd, \ - (_request), \ - "%s%s%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - (_script) ? ", \"" : "", \ - (_script) ? (_script)->script : "", \ - (_script) ? "\"" : "" \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } G_STMT_END - -#define _LOG_X_(enabled_cmd, print_cmd, ...) \ - G_STMT_START { \ - if (enabled_cmd) \ - __LOG_print (print_cmd, __VA_ARGS__); \ - } G_STMT_END - -#define _LOG_R_(enabled_cmd, x_request, print_cmd, ...) \ - G_STMT_START { \ - const Request *const _request = (x_request); \ - \ - nm_assert (_request); \ - if (enabled_cmd) \ - __LOG_print_R (print_cmd, _request, ": "__VA_ARGS__); \ - } G_STMT_END - -#define _LOG_S_(enabled_cmd, x_script, print_cmd, ...) \ - G_STMT_START { \ - const ScriptInfo *const _script = (x_script); \ - const Request *const _request = _script ? _script->request : NULL; \ - \ - nm_assert (_script && _request); \ - if (enabled_cmd) \ - __LOG_print_S (print_cmd, _request, _script, ": "__VA_ARGS__); \ - } G_STMT_END +#define __LOG_print(print_cmd, ...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + /* g_message() alone does not warn about invalid format. Add a dummy printf() statement to + * get a compiler warning about wrong format. */ \ + printf(__VA_ARGS__); \ + } \ + print_cmd(__VA_ARGS__); \ + } \ + G_STMT_END + +#define __LOG_print_R(print_cmd, _request, ...) \ + G_STMT_START \ + { \ + __LOG_print(print_cmd, \ + "req:%u '%s'%s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + (_request)->request_id, \ + (_request)->action, \ + (_request)->iface ? " [" : "", \ + (_request)->iface ?: "", \ + (_request)->iface ? "]" : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + G_STMT_END + +#define __LOG_print_S(print_cmd, _request, _script, ...) \ + G_STMT_START \ + { \ + __LOG_print_R(print_cmd, \ + (_request), \ + "%s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + (_script) ? ", \"" : "", \ + (_script) ? (_script)->script : "", \ + (_script) ? "\"" : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + G_STMT_END + +#define _LOG_X_(enabled_cmd, print_cmd, ...) \ + G_STMT_START \ + { \ + if (enabled_cmd) \ + __LOG_print(print_cmd, __VA_ARGS__); \ + } \ + G_STMT_END + +#define _LOG_R_(enabled_cmd, x_request, print_cmd, ...) \ + G_STMT_START \ + { \ + const Request *const _request = (x_request); \ + \ + nm_assert(_request); \ + if (enabled_cmd) \ + __LOG_print_R(print_cmd, _request, ": "__VA_ARGS__); \ + } \ + G_STMT_END + +#define _LOG_S_(enabled_cmd, x_script, print_cmd, ...) \ + G_STMT_START \ + { \ + const ScriptInfo *const _script = (x_script); \ + const Request *const _request = _script ? _script->request : NULL; \ + \ + nm_assert(_script &&_request); \ + if (enabled_cmd) \ + __LOG_print_S(print_cmd, _request, _script, ": "__VA_ARGS__); \ + } \ + G_STMT_END #define _LOG_X_D_enabled() (gl.debug) -#define _LOG_X_T_enabled() _LOG_X_D_enabled () +#define _LOG_X_T_enabled() _LOG_X_D_enabled() -#define _LOG_R_D_enabled(request) (_NM_ENSURE_TYPE_CONST (Request *, request)->debug) -#define _LOG_R_T_enabled(request) _LOG_R_D_enabled (request) +#define _LOG_R_D_enabled(request) (_NM_ENSURE_TYPE_CONST(Request *, request)->debug) +#define _LOG_R_T_enabled(request) _LOG_R_D_enabled(request) -#define _LOG_X_T(...) _LOG_X_ (_LOG_X_T_enabled (), g_debug, __VA_ARGS__) -#define _LOG_X_D(...) _LOG_X_ (_LOG_X_D_enabled (), g_info, __VA_ARGS__) -#define _LOG_X_I(...) _LOG_X_ (TRUE, g_message, __VA_ARGS__) -#define _LOG_X_W(...) _LOG_X_ (TRUE, g_warning, __VA_ARGS__) +#define _LOG_X_T(...) _LOG_X_(_LOG_X_T_enabled(), g_debug, __VA_ARGS__) +#define _LOG_X_D(...) _LOG_X_(_LOG_X_D_enabled(), g_info, __VA_ARGS__) +#define _LOG_X_I(...) _LOG_X_(TRUE, g_message, __VA_ARGS__) +#define _LOG_X_W(...) _LOG_X_(TRUE, g_warning, __VA_ARGS__) -#define _LOG_R_T(request, ...) _LOG_R_ (_LOG_R_T_enabled (_request), request, g_debug, __VA_ARGS__) -#define _LOG_R_D(request, ...) _LOG_R_ (_LOG_R_D_enabled (_request), request, g_info, __VA_ARGS__) -#define _LOG_R_W(request, ...) _LOG_R_ (TRUE, request, g_warning, __VA_ARGS__) +#define _LOG_R_T(request, ...) _LOG_R_(_LOG_R_T_enabled(_request), request, g_debug, __VA_ARGS__) +#define _LOG_R_D(request, ...) _LOG_R_(_LOG_R_D_enabled(_request), request, g_info, __VA_ARGS__) +#define _LOG_R_W(request, ...) _LOG_R_(TRUE, request, g_warning, __VA_ARGS__) -#define _LOG_S_T(script, ...) _LOG_S_ (_LOG_R_T_enabled (_request), script, g_debug, __VA_ARGS__) -#define _LOG_S_D(script, ...) _LOG_S_ (_LOG_R_D_enabled (_request), script, g_info, __VA_ARGS__) -#define _LOG_S_W(script, ...) _LOG_S_ (TRUE, script, g_warning, __VA_ARGS__) +#define _LOG_S_T(script, ...) _LOG_S_(_LOG_R_T_enabled(_request), script, g_debug, __VA_ARGS__) +#define _LOG_S_D(script, ...) _LOG_S_(_LOG_R_D_enabled(_request), script, g_info, __VA_ARGS__) +#define _LOG_S_W(script, ...) _LOG_S_(TRUE, script, g_warning, __VA_ARGS__) /*****************************************************************************/ -static gboolean dispatch_one_script (Request *request); +static gboolean dispatch_one_script(Request *request); /*****************************************************************************/ static void -script_info_free (gpointer ptr) +script_info_free(gpointer ptr) { - ScriptInfo *info = ptr; + ScriptInfo *info = ptr; - g_free (info->script); - g_free (info->error); - g_slice_free (ScriptInfo, info); + g_free(info->script); + g_free(info->error); + g_slice_free(ScriptInfo, info); } static void -request_free (Request *request) +request_free(Request *request) { - g_assert_cmpuint (request->num_scripts_done, ==, request->scripts->len); - g_assert_cmpuint (request->num_scripts_nowait, ==, 0); + g_assert_cmpuint(request->num_scripts_done, ==, request->scripts->len); + g_assert_cmpuint(request->num_scripts_nowait, ==, 0); - g_free (request->action); - g_free (request->iface); - g_strfreev (request->envp); - g_ptr_array_free (request->scripts, TRUE); + g_free(request->action); + g_free(request->iface); + g_strfreev(request->envp); + g_ptr_array_free(request->scripts, TRUE); - g_slice_free (Request, request); + g_slice_free(Request, request); } static gboolean -quit_timeout_cb (gpointer user_data) +quit_timeout_cb(gpointer user_data) { - gl.quit_id = 0; - g_main_loop_quit (gl.loop); - return G_SOURCE_REMOVE; + gl.quit_id = 0; + g_main_loop_quit(gl.loop); + return G_SOURCE_REMOVE; } static void -quit_timeout_reschedule (void) +quit_timeout_reschedule(void) { - if (!gl.persist) { - nm_clear_g_source (&gl.quit_id); - gl.quit_id = g_timeout_add_seconds (10, quit_timeout_cb, NULL); - } + if (!gl.persist) { + nm_clear_g_source(&gl.quit_id); + gl.quit_id = g_timeout_add_seconds(10, quit_timeout_cb, NULL); + } } /** @@ -207,29 +217,29 @@ quit_timeout_reschedule (void) * a new request as current. */ static gboolean -next_request (Request *request) +next_request(Request *request) { - if (request) { - if (gl.current_request) { - g_queue_push_tail (gl.requests_waiting, request); - return FALSE; - } - } else { - /* when calling next_request() without explicit @request, we always - * forcefully clear @current_request. That one is certainly - * handled already. */ - gl.current_request = NULL; - - request = g_queue_pop_head (gl.requests_waiting); - if (!request) - return FALSE; - } - - _LOG_R_D (request, "start running ordered scripts..."); - - gl.current_request = request; - - return TRUE; + if (request) { + if (gl.current_request) { + g_queue_push_tail(gl.requests_waiting, request); + return FALSE; + } + } else { + /* when calling next_request() without explicit @request, we always + * forcefully clear @current_request. That one is certainly + * handled already. */ + gl.current_request = NULL; + + request = g_queue_pop_head(gl.requests_waiting); + if (!request) + return FALSE; + } + + _LOG_R_D(request, "start running ordered scripts..."); + + gl.current_request = request; + + return TRUE; } /** @@ -242,862 +252,850 @@ next_request (Request *request) * It also decreases @num_requests_pending and possibly does quit_timeout_reschedule(). */ static void -complete_request (Request *request) +complete_request(Request *request) { - GVariantBuilder results; - GVariant *ret; - guint i; + GVariantBuilder results; + GVariant * ret; + guint i; - nm_assert (request); + nm_assert(request); - /* Are there still pending scripts? Then do nothing (for now). */ - if (request->num_scripts_done < request->scripts->len) - return; + /* Are there still pending scripts? Then do nothing (for now). */ + if (request->num_scripts_done < request->scripts->len) + return; - g_variant_builder_init (&results, G_VARIANT_TYPE ("a(sus)")); - for (i = 0; i < request->scripts->len; i++) { - ScriptInfo *script = g_ptr_array_index (request->scripts, i); + g_variant_builder_init(&results, G_VARIANT_TYPE("a(sus)")); + for (i = 0; i < request->scripts->len; i++) { + ScriptInfo *script = g_ptr_array_index(request->scripts, i); - g_variant_builder_add (&results, "(sus)", - script->script, - script->result, - script->error ?: ""); - } + g_variant_builder_add(&results, + "(sus)", + script->script, + script->result, + script->error ?: ""); + } - ret = g_variant_new ("(a(sus))", &results); - g_dbus_method_invocation_return_value (request->context, ret); + ret = g_variant_new("(a(sus))", &results); + g_dbus_method_invocation_return_value(request->context, ret); - _LOG_R_T (request, "completed (%u scripts)", request->scripts->len); + _LOG_R_T(request, "completed (%u scripts)", request->scripts->len); - if (gl.current_request == request) - gl.current_request = NULL; + if (gl.current_request == request) + gl.current_request = NULL; - request_free (request); + request_free(request); - g_assert_cmpuint (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 (); - } + g_assert_cmpuint(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(); + } } static void -complete_script (ScriptInfo *script) +complete_script(ScriptInfo *script) { - Request *request; - gboolean wait = script->wait; - - request = script->request; - - if (wait) { - /* for "wait" scripts, try to schedule the next blocking script. - * If that is successful, return (as we must wait for its completion). */ - if (dispatch_one_script (request)) - return; - } - - nm_assert (!wait || gl.current_request == request); - - /* Try to complete the request. @request will be possibly free'd, - * making @script and @request a dangling pointer. */ - complete_request (request); - - if (!wait) { - /* this was a "no-wait" script. We either completed the request, - * or there is nothing to do. Especially, there is no need to - * queue the next_request() -- because no-wait scripts don't block - * requests. However, if this was the last "no-wait" script and - * there are "wait" scripts ready to run, launch them. - */ - if ( gl.current_request == request - && gl.current_request->num_scripts_nowait == 0) { - - if (dispatch_one_script (gl.current_request)) - return; - - complete_request (gl.current_request); - } else - return; - } else { - /* if the script is a "wait" script, we already tried above to - * dispatch the next script. As we didn't do that, it means we - * just completed the last script of @request and we can continue - * with the next request... - * - * Also, it cannot be that there is another request currently being - * processed because only requests with "wait" scripts can become - * @current_request. As there can only be one "wait" script running - * at any time, it means complete_request() above completed @request. */ - nm_assert (!gl.current_request); - } - - while (next_request (NULL)) { - request = gl.current_request; - - if (dispatch_one_script (request)) - return; - - /* Try to complete the request. It will be either completed - * now, or when all pending "no-wait" scripts return. */ - complete_request (request); - - /* We can immediately start next_request(), because our current - * @request has obviously no more "wait" scripts either. - * Repeat... */ - } + Request *request; + gboolean wait = script->wait; + + request = script->request; + + if (wait) { + /* for "wait" scripts, try to schedule the next blocking script. + * If that is successful, return (as we must wait for its completion). */ + if (dispatch_one_script(request)) + return; + } + + nm_assert(!wait || gl.current_request == request); + + /* Try to complete the request. @request will be possibly free'd, + * making @script and @request a dangling pointer. */ + complete_request(request); + + if (!wait) { + /* this was a "no-wait" script. We either completed the request, + * or there is nothing to do. Especially, there is no need to + * queue the next_request() -- because no-wait scripts don't block + * requests. However, if this was the last "no-wait" script and + * there are "wait" scripts ready to run, launch them. + */ + if (gl.current_request == request && gl.current_request->num_scripts_nowait == 0) { + if (dispatch_one_script(gl.current_request)) + return; + + complete_request(gl.current_request); + } else + return; + } else { + /* if the script is a "wait" script, we already tried above to + * dispatch the next script. As we didn't do that, it means we + * just completed the last script of @request and we can continue + * with the next request... + * + * Also, it cannot be that there is another request currently being + * processed because only requests with "wait" scripts can become + * @current_request. As there can only be one "wait" script running + * at any time, it means complete_request() above completed @request. */ + nm_assert(!gl.current_request); + } + + while (next_request(NULL)) { + request = gl.current_request; + + if (dispatch_one_script(request)) + return; + + /* Try to complete the request. It will be either completed + * now, or when all pending "no-wait" scripts return. */ + complete_request(request); + + /* We can immediately start next_request(), because our current + * @request has obviously no more "wait" scripts either. + * Repeat... */ + } } static void -script_watch_cb (GPid pid, int status, gpointer user_data) +script_watch_cb(GPid pid, int status, gpointer user_data) { - ScriptInfo *script = user_data; - guint err; - - g_assert (pid == script->pid); - - script->watch_id = 0; - nm_clear_g_source (&script->timeout_id); - script->request->num_scripts_done++; - if (!script->wait) - script->request->num_scripts_nowait--; - - if (WIFEXITED (status)) { - err = WEXITSTATUS (status); - if (err == 0) - script->result = DISPATCH_RESULT_SUCCESS; - else { - script->error = g_strdup_printf ("Script '%s' exited with error status %d.", - script->script, err); - } - } else if (WIFSTOPPED (status)) { - script->error = g_strdup_printf ("Script '%s' stopped unexpectedly with signal %d.", - script->script, WSTOPSIG (status)); - } else if (WIFSIGNALED (status)) { - script->error = g_strdup_printf ("Script '%s' died with signal %d", - script->script, WTERMSIG (status)); - } else { - script->error = g_strdup_printf ("Script '%s' died from an unknown cause", - script->script); - } - - if (script->result == DISPATCH_RESULT_SUCCESS) { - _LOG_S_T (script, "complete"); - } else { - script->result = DISPATCH_RESULT_FAILED; - _LOG_S_W (script, "complete: failed with %s", script->error); - } - - g_spawn_close_pid (script->pid); - - complete_script (script); + ScriptInfo *script = user_data; + guint err; + + g_assert(pid == script->pid); + + script->watch_id = 0; + nm_clear_g_source(&script->timeout_id); + script->request->num_scripts_done++; + if (!script->wait) + script->request->num_scripts_nowait--; + + if (WIFEXITED(status)) { + err = WEXITSTATUS(status); + if (err == 0) + script->result = DISPATCH_RESULT_SUCCESS; + else { + script->error = + g_strdup_printf("Script '%s' exited with error status %d.", script->script, err); + } + } else if (WIFSTOPPED(status)) { + script->error = g_strdup_printf("Script '%s' stopped unexpectedly with signal %d.", + script->script, + WSTOPSIG(status)); + } else if (WIFSIGNALED(status)) { + script->error = + g_strdup_printf("Script '%s' died with signal %d", script->script, WTERMSIG(status)); + } else { + script->error = g_strdup_printf("Script '%s' died from an unknown cause", script->script); + } + + if (script->result == DISPATCH_RESULT_SUCCESS) { + _LOG_S_T(script, "complete"); + } else { + script->result = DISPATCH_RESULT_FAILED; + _LOG_S_W(script, "complete: failed with %s", script->error); + } + + g_spawn_close_pid(script->pid); + + complete_script(script); } static gboolean -script_timeout_cb (gpointer user_data) +script_timeout_cb(gpointer user_data) { - ScriptInfo *script = user_data; + ScriptInfo *script = user_data; - script->timeout_id = 0; - nm_clear_g_source (&script->watch_id); - script->request->num_scripts_done++; - if (!script->wait) - script->request->num_scripts_nowait--; + script->timeout_id = 0; + nm_clear_g_source(&script->watch_id); + script->request->num_scripts_done++; + if (!script->wait) + script->request->num_scripts_nowait--; - _LOG_S_W (script, "complete: timeout (kill script)"); + _LOG_S_W(script, "complete: timeout (kill script)"); - kill (script->pid, SIGKILL); + kill(script->pid, SIGKILL); again: - if (waitpid (script->pid, NULL, 0) == -1) { - if (errno == EINTR) - goto again; - } + if (waitpid(script->pid, NULL, 0) == -1) { + if (errno == EINTR) + goto again; + } - script->error = g_strdup_printf ("Script '%s' timed out.", script->script); - script->result = DISPATCH_RESULT_TIMEOUT; + script->error = g_strdup_printf("Script '%s' timed out.", script->script); + script->result = DISPATCH_RESULT_TIMEOUT; - g_spawn_close_pid (script->pid); + g_spawn_close_pid(script->pid); - complete_script (script); + complete_script(script); - return FALSE; + return FALSE; } static gboolean -check_permissions (struct stat *s, const char **out_error_msg) +check_permissions(struct stat *s, const char **out_error_msg) { - g_return_val_if_fail (s != NULL, FALSE); - g_return_val_if_fail (out_error_msg != NULL, FALSE); - g_return_val_if_fail (*out_error_msg == NULL, FALSE); - - /* Only accept files owned by root */ - if (s->st_uid != 0) { - *out_error_msg = "not owned by root."; - return FALSE; - } - - /* Only accept files not writable by group or other, and not SUID */ - if (s->st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - *out_error_msg = "writable by group or other, or set-UID."; - return FALSE; - } - - /* Only accept files executable by the owner */ - if (!(s->st_mode & S_IXUSR)) { - *out_error_msg = "not executable by owner."; - return FALSE; - } - - return TRUE; + g_return_val_if_fail(s != NULL, FALSE); + g_return_val_if_fail(out_error_msg != NULL, FALSE); + g_return_val_if_fail(*out_error_msg == NULL, FALSE); + + /* Only accept files owned by root */ + if (s->st_uid != 0) { + *out_error_msg = "not owned by root."; + return FALSE; + } + + /* Only accept files not writable by group or other, and not SUID */ + if (s->st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { + *out_error_msg = "writable by group or other, or set-UID."; + return FALSE; + } + + /* Only accept files executable by the owner */ + if (!(s->st_mode & S_IXUSR)) { + *out_error_msg = "not executable by owner."; + return FALSE; + } + + return TRUE; } static gboolean -check_filename (const char *file_name) +check_filename(const char *file_name) { - static const char *bad_suffixes[] = { - "~", - ".rpmsave", - ".rpmorig", - ".rpmnew", - ".swp", - }; - char *tmp; - guint i; - - /* File must not be a backup file, package management file, or start with '.' */ - - if (file_name[0] == '.') - return FALSE; - for (i = 0; i < G_N_ELEMENTS (bad_suffixes); i++) { - if (g_str_has_suffix (file_name, bad_suffixes[i])) - return FALSE; - } - tmp = g_strrstr (file_name, ".dpkg-"); - if (tmp && !strchr (&tmp[1], '.')) - return FALSE; - return TRUE; + static const char *bad_suffixes[] = { + "~", + ".rpmsave", + ".rpmorig", + ".rpmnew", + ".swp", + }; + char *tmp; + guint i; + + /* File must not be a backup file, package management file, or start with '.' */ + + if (file_name[0] == '.') + return FALSE; + for (i = 0; i < G_N_ELEMENTS(bad_suffixes); i++) { + if (g_str_has_suffix(file_name, bad_suffixes[i])) + return FALSE; + } + tmp = g_strrstr(file_name, ".dpkg-"); + if (tmp && !strchr(&tmp[1], '.')) + return FALSE; + return TRUE; } -#define SCRIPT_TIMEOUT 600 /* 10 minutes */ +#define SCRIPT_TIMEOUT 600 /* 10 minutes */ static gboolean -script_dispatch (ScriptInfo *script) +script_dispatch(ScriptInfo *script) { - gs_free_error GError *error = NULL; - char *argv[4]; - Request *request = script->request; - - if (script->dispatched) - return FALSE; - - script->dispatched = TRUE; - - /* Only for "hostname" action we coerce the interface name to "none". We don't - * do so for "connectivity-check" action. */ - - argv[0] = script->script; - argv[1] = request->iface - ?: (nm_streq (request->action, NMD_ACTION_HOSTNAME) ? "none" : ""); - argv[2] = request->action; - argv[3] = NULL; - - _LOG_S_T (script, "run script%s", script->wait ? "" : " (no-wait)"); - - if (!g_spawn_async ("/", argv, request->envp, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &script->pid, &error)) { - _LOG_S_W (script, "complete: failed to execute script: %s", error->message); - script->result = DISPATCH_RESULT_EXEC_FAILED; - script->error = g_strdup (error->message); - request->num_scripts_done++; - return FALSE; - } - - script->watch_id = g_child_watch_add (script->pid, (GChildWatchFunc) script_watch_cb, script); - script->timeout_id = g_timeout_add_seconds (SCRIPT_TIMEOUT, script_timeout_cb, script); - if (!script->wait) - request->num_scripts_nowait++; - return TRUE; + gs_free_error GError *error = NULL; + char * argv[4]; + Request * request = script->request; + + if (script->dispatched) + return FALSE; + + script->dispatched = TRUE; + + /* Only for "hostname" action we coerce the interface name to "none". We don't + * do so for "connectivity-check" action. */ + + argv[0] = script->script; + argv[1] = request->iface ?: (nm_streq(request->action, NMD_ACTION_HOSTNAME) ? "none" : ""); + argv[2] = request->action; + argv[3] = NULL; + + _LOG_S_T(script, "run script%s", script->wait ? "" : " (no-wait)"); + + if (!g_spawn_async("/", + argv, + request->envp, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &script->pid, + &error)) { + _LOG_S_W(script, "complete: failed to execute script: %s", error->message); + script->result = DISPATCH_RESULT_EXEC_FAILED; + script->error = g_strdup(error->message); + request->num_scripts_done++; + return FALSE; + } + + script->watch_id = g_child_watch_add(script->pid, (GChildWatchFunc) script_watch_cb, script); + script->timeout_id = g_timeout_add_seconds(SCRIPT_TIMEOUT, script_timeout_cb, script); + if (!script->wait) + request->num_scripts_nowait++; + return TRUE; } static gboolean -dispatch_one_script (Request *request) +dispatch_one_script(Request *request) { - if (request->num_scripts_nowait > 0) - return TRUE; + if (request->num_scripts_nowait > 0) + return TRUE; - while (request->idx < request->scripts->len) { - ScriptInfo *script; + while (request->idx < request->scripts->len) { + ScriptInfo *script; - script = g_ptr_array_index (request->scripts, request->idx++); - if (script_dispatch (script)) - return TRUE; - } - return FALSE; + script = g_ptr_array_index(request->scripts, request->idx++); + if (script_dispatch(script)) + return TRUE; + } + return FALSE; } static int -_compare_basenames (gconstpointer a, gconstpointer b) +_compare_basenames(gconstpointer a, gconstpointer b) { - const char *basename_a = strrchr (a, '/'); - const char *basename_b = strrchr (b, '/'); - int ret; + const char *basename_a = strrchr(a, '/'); + const char *basename_b = strrchr(b, '/'); + int ret; - nm_assert (basename_a); - nm_assert (basename_b); + nm_assert(basename_a); + nm_assert(basename_b); - ret = strcmp (++basename_a, ++basename_b); - if (ret) - return ret; + ret = strcmp(++basename_a, ++basename_b); + if (ret) + return ret; - nm_assert_not_reached (); - return 0; + nm_assert_not_reached(); + return 0; } static void -_find_scripts (Request *request, GHashTable *scripts, const char *base, const char *subdir) +_find_scripts(Request *request, GHashTable *scripts, const char *base, const char *subdir) { - const char *filename; - gs_free char *dirname = NULL; - GError *error = NULL; - GDir *dir; - - dirname = g_build_filename (base, "dispatcher.d", subdir, NULL); - - if (!(dir = g_dir_open (dirname, 0, &error))) { - if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { - _LOG_R_W (request, "find-scripts: Failed to open dispatcher directory '%s': %s", - dirname, error->message); - } - g_error_free (error); - return; - } - - while ((filename = g_dir_read_name (dir))) { - if (!check_filename (filename)) - continue; - - g_hash_table_insert (scripts, - g_strdup (filename), - g_build_filename (dirname, filename, NULL)); - } - - g_dir_close (dir); + const char * filename; + gs_free char *dirname = NULL; + GError * error = NULL; + GDir * dir; + + dirname = g_build_filename(base, "dispatcher.d", subdir, NULL); + + if (!(dir = g_dir_open(dirname, 0, &error))) { + if (!g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { + _LOG_R_W(request, + "find-scripts: Failed to open dispatcher directory '%s': %s", + dirname, + error->message); + } + g_error_free(error); + return; + } + + while ((filename = g_dir_read_name(dir))) { + if (!check_filename(filename)) + continue; + + g_hash_table_insert(scripts, g_strdup(filename), g_build_filename(dirname, filename, NULL)); + } + + g_dir_close(dir); } static GSList * -find_scripts (Request *request) +find_scripts(Request *request) { - gs_unref_hashtable GHashTable *scripts = NULL; - GSList *script_list = NULL; - GHashTableIter iter; - const char *subdir; - char *path; - char *filename; - - if (NM_IN_STRSET (request->action, NMD_ACTION_PRE_UP, - NMD_ACTION_VPN_PRE_UP)) - subdir = "pre-up.d"; - else if (NM_IN_STRSET (request->action, NMD_ACTION_PRE_DOWN, - NMD_ACTION_VPN_PRE_DOWN)) - subdir = "pre-down.d"; - else - subdir = NULL; - - scripts = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - - _find_scripts (request, scripts, NMLIBDIR, subdir); - _find_scripts (request, scripts, NMCONFDIR, subdir); - - g_hash_table_iter_init (&iter, scripts); - while (g_hash_table_iter_next (&iter, (gpointer *) &filename, (gpointer *) &path)) { - gs_free char *link_target = NULL; - const char *err_msg = NULL; - struct stat st; - int err; - - link_target = g_file_read_link (path, NULL); - if (nm_streq0 (link_target, "/dev/null")) - continue; - - err = stat (path, &st); - if (err) - _LOG_R_W (request, "find-scripts: Failed to stat '%s': %d", path, err); - else if ( !S_ISREG (st.st_mode) - || st.st_size == 0) { - /* silently skip. */ - } else if (!check_permissions (&st, &err_msg)) - _LOG_R_W (request, "find-scripts: Cannot execute '%s': %s", path, err_msg); - else { - /* success */ - script_list = g_slist_prepend (script_list, g_strdup (path)); - continue; - } - } - - return g_slist_sort (script_list, _compare_basenames); + gs_unref_hashtable GHashTable *scripts = NULL; + GSList * script_list = NULL; + GHashTableIter iter; + const char * subdir; + char * path; + char * filename; + + if (NM_IN_STRSET(request->action, NMD_ACTION_PRE_UP, NMD_ACTION_VPN_PRE_UP)) + subdir = "pre-up.d"; + else if (NM_IN_STRSET(request->action, NMD_ACTION_PRE_DOWN, NMD_ACTION_VPN_PRE_DOWN)) + subdir = "pre-down.d"; + else + subdir = NULL; + + scripts = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); + + _find_scripts(request, scripts, NMLIBDIR, subdir); + _find_scripts(request, scripts, NMCONFDIR, subdir); + + g_hash_table_iter_init(&iter, scripts); + while (g_hash_table_iter_next(&iter, (gpointer *) &filename, (gpointer *) &path)) { + gs_free char *link_target = NULL; + const char * err_msg = NULL; + struct stat st; + int err; + + link_target = g_file_read_link(path, NULL); + if (nm_streq0(link_target, "/dev/null")) + continue; + + err = stat(path, &st); + if (err) + _LOG_R_W(request, "find-scripts: Failed to stat '%s': %d", path, err); + else if (!S_ISREG(st.st_mode) || st.st_size == 0) { + /* silently skip. */ + } else if (!check_permissions(&st, &err_msg)) + _LOG_R_W(request, "find-scripts: Cannot execute '%s': %s", path, err_msg); + else { + /* success */ + script_list = g_slist_prepend(script_list, g_strdup(path)); + continue; + } + } + + return g_slist_sort(script_list, _compare_basenames); } static gboolean -script_must_wait (const char *path) +script_must_wait(const char *path) { - gs_free char *link = NULL; - - link = g_file_read_link (path, NULL); - if (link) { - gs_free char *dir = NULL; - nm_auto_free char *real = NULL; - - if (!g_path_is_absolute (link)) { - char *tmp; - - dir = g_path_get_dirname (path); - tmp = g_build_path ("/", dir, link, NULL); - g_free (link); - g_free (dir); - link = tmp; - } - - dir = g_path_get_dirname (link); - real = realpath (dir, NULL); - if (NM_STR_HAS_SUFFIX (real, "/no-wait.d")) - return FALSE; - } - - return TRUE; + gs_free char *link = NULL; + + link = g_file_read_link(path, NULL); + if (link) { + gs_free char * dir = NULL; + nm_auto_free char *real = NULL; + + if (!g_path_is_absolute(link)) { + char *tmp; + + dir = g_path_get_dirname(path); + tmp = g_build_path("/", dir, link, NULL); + g_free(link); + g_free(dir); + link = tmp; + } + + dir = g_path_get_dirname(link); + real = realpath(dir, NULL); + if (NM_STR_HAS_SUFFIX(real, "/no-wait.d")) + return FALSE; + } + + return TRUE; } static void -_method_call_action (GDBusMethodInvocation *invocation, - GVariant *parameters) +_method_call_action(GDBusMethodInvocation *invocation, GVariant *parameters) { - const char *action; - gs_unref_variant GVariant *connection = NULL; - gs_unref_variant GVariant *connection_properties = NULL; - gs_unref_variant GVariant *device_properties = NULL; - gs_unref_variant GVariant *device_proxy_properties = NULL; - gs_unref_variant GVariant *device_ip4_config = NULL; - gs_unref_variant GVariant *device_ip6_config = NULL; - gs_unref_variant GVariant *device_dhcp4_config = NULL; - gs_unref_variant GVariant *device_dhcp6_config = NULL; - const char *connectivity_state; - const char *vpn_ip_iface; - gs_unref_variant GVariant *vpn_proxy_properties = NULL; - gs_unref_variant GVariant *vpn_ip4_config = NULL; - gs_unref_variant GVariant *vpn_ip6_config = NULL; - gboolean debug; - GSList *sorted_scripts = NULL; - GSList *iter; - Request *request; - char **p; - guint i, num_nowait = 0; - const char *error_message = NULL; - - g_variant_get (parameters, "(" - "&s" /* action */ - "@a{sa{sv}}" /* connection */ - "@a{sv}" /* connection_properties */ - "@a{sv}" /* device_properties */ - "@a{sv}" /* device_proxy_properties */ - "@a{sv}" /* device_ip4_config */ - "@a{sv}" /* device_ip6_config */ - "@a{sv}" /* device_dhcp4_config */ - "@a{sv}" /* device_dhcp6_config */ - "&s" /* connectivity_state */ - "&s" /* vpn_ip_iface */ - "@a{sv}" /* vpn_proxy_properties */ - "@a{sv}" /* vpn_ip4_config */ - "@a{sv}" /* vpn_ip6_config */ - "b" /* debug */ - ")", - &action, - &connection, - &connection_properties, - &device_properties, - &device_proxy_properties, - &device_ip4_config, - &device_ip6_config, - &device_dhcp4_config, - &device_dhcp6_config, - &connectivity_state, - &vpn_ip_iface, - &vpn_proxy_properties, - &vpn_ip4_config, - &vpn_ip6_config, - &debug); - - request = g_slice_new0 (Request); - request->request_id = ++gl.request_id_counter; - request->debug = debug || gl.debug; - request->context = invocation; - request->action = g_strdup (action); - - request->envp = nm_dispatcher_utils_construct_envp (action, - connection, - connection_properties, - device_properties, - device_proxy_properties, - device_ip4_config, - device_ip6_config, - device_dhcp4_config, - device_dhcp6_config, - connectivity_state, - vpn_ip_iface, - vpn_proxy_properties, - vpn_ip4_config, - vpn_ip6_config, - &request->iface, - &error_message); - - request->scripts = g_ptr_array_new_full (5, script_info_free); - - sorted_scripts = find_scripts (request); - for (iter = sorted_scripts; iter; iter = g_slist_next (iter)) { - ScriptInfo *s; - - s = g_slice_new0 (ScriptInfo); - s->request = request; - s->script = iter->data; - s->wait = script_must_wait (s->script); - g_ptr_array_add (request->scripts, s); - } - g_slist_free (sorted_scripts); - - _LOG_R_D (request, "new request (%u scripts)", request->scripts->len); - if ( _LOG_R_T_enabled (request) - && request->envp) { - for (p = request->envp; *p; p++) - _LOG_R_T (request, "environment: %s", *p); - } - - if (error_message || request->scripts->len == 0) { - GVariant *results; - - if (error_message) - _LOG_R_W (request, "completed: invalid request: %s", error_message); - else - _LOG_R_D (request, "completed: no scripts"); - - results = g_variant_new_array (G_VARIANT_TYPE ("(sus)"), NULL, 0); - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(sus))", results)); - request->num_scripts_done = request->scripts->len; - request_free (request); - return; - } - - nm_clear_g_source (&gl.quit_id); - - gl.num_requests_pending++; - - for (i = 0; i < request->scripts->len; i++) { - ScriptInfo *s = g_ptr_array_index (request->scripts, i); - - if (!s->wait) { - script_dispatch (s); - num_nowait++; - } - } - - if (num_nowait < request->scripts->len) { - /* The request has at least one wait script. - * Try next_request() to schedule the request for - * execution. This either enqueues the request or - * sets it as gl.current_request. */ - if (next_request (request)) { - /* @request is now @current_request. Go ahead and - * schedule the first wait script. */ - if (!dispatch_one_script (request)) { - /* If that fails, we might be already finished with the - * request. Try complete_request(). */ - complete_request (request); - - if (next_request (NULL)) { - /* As @request was successfully scheduled as next_request(), there is no - * other request in queue that can be scheduled afterwards. Assert against - * that, but call next_request() to clear current_request. */ - g_assert_not_reached (); - } - } - } - } else { - /* The request contains only no-wait scripts. Try to complete - * the request right away (we might have failed to schedule any - * of the scripts). It will be either completed now, or later - * when the pending scripts return. - * We don't enqueue it to gl.requests_waiting. - * There is no need to handle next_request(), because @request is - * not the current request anyway and does not interfere with requests - * that have any "wait" scripts. */ - complete_request (request); - } + const char * action; + gs_unref_variant GVariant *connection = NULL; + gs_unref_variant GVariant *connection_properties = NULL; + gs_unref_variant GVariant *device_properties = NULL; + gs_unref_variant GVariant *device_proxy_properties = NULL; + gs_unref_variant GVariant *device_ip4_config = NULL; + gs_unref_variant GVariant *device_ip6_config = NULL; + gs_unref_variant GVariant *device_dhcp4_config = NULL; + gs_unref_variant GVariant *device_dhcp6_config = NULL; + const char * connectivity_state; + const char * vpn_ip_iface; + gs_unref_variant GVariant *vpn_proxy_properties = NULL; + gs_unref_variant GVariant *vpn_ip4_config = NULL; + gs_unref_variant GVariant *vpn_ip6_config = NULL; + gboolean debug; + GSList * sorted_scripts = NULL; + GSList * iter; + Request * request; + char ** p; + guint i, num_nowait = 0; + const char * error_message = NULL; + + g_variant_get(parameters, + "(" + "&s" /* action */ + "@a{sa{sv}}" /* connection */ + "@a{sv}" /* connection_properties */ + "@a{sv}" /* device_properties */ + "@a{sv}" /* device_proxy_properties */ + "@a{sv}" /* device_ip4_config */ + "@a{sv}" /* device_ip6_config */ + "@a{sv}" /* device_dhcp4_config */ + "@a{sv}" /* device_dhcp6_config */ + "&s" /* connectivity_state */ + "&s" /* vpn_ip_iface */ + "@a{sv}" /* vpn_proxy_properties */ + "@a{sv}" /* vpn_ip4_config */ + "@a{sv}" /* vpn_ip6_config */ + "b" /* debug */ + ")", + &action, + &connection, + &connection_properties, + &device_properties, + &device_proxy_properties, + &device_ip4_config, + &device_ip6_config, + &device_dhcp4_config, + &device_dhcp6_config, + &connectivity_state, + &vpn_ip_iface, + &vpn_proxy_properties, + &vpn_ip4_config, + &vpn_ip6_config, + &debug); + + request = g_slice_new0(Request); + request->request_id = ++gl.request_id_counter; + request->debug = debug || gl.debug; + request->context = invocation; + request->action = g_strdup(action); + + request->envp = nm_dispatcher_utils_construct_envp(action, + connection, + connection_properties, + device_properties, + device_proxy_properties, + device_ip4_config, + device_ip6_config, + device_dhcp4_config, + device_dhcp6_config, + connectivity_state, + vpn_ip_iface, + vpn_proxy_properties, + vpn_ip4_config, + vpn_ip6_config, + &request->iface, + &error_message); + + request->scripts = g_ptr_array_new_full(5, script_info_free); + + sorted_scripts = find_scripts(request); + for (iter = sorted_scripts; iter; iter = g_slist_next(iter)) { + ScriptInfo *s; + + s = g_slice_new0(ScriptInfo); + s->request = request; + s->script = iter->data; + s->wait = script_must_wait(s->script); + g_ptr_array_add(request->scripts, s); + } + g_slist_free(sorted_scripts); + + _LOG_R_D(request, "new request (%u scripts)", request->scripts->len); + if (_LOG_R_T_enabled(request) && request->envp) { + for (p = request->envp; *p; p++) + _LOG_R_T(request, "environment: %s", *p); + } + + if (error_message || request->scripts->len == 0) { + GVariant *results; + + if (error_message) + _LOG_R_W(request, "completed: invalid request: %s", error_message); + else + _LOG_R_D(request, "completed: no scripts"); + + results = g_variant_new_array(G_VARIANT_TYPE("(sus)"), NULL, 0); + g_dbus_method_invocation_return_value(invocation, g_variant_new("(@a(sus))", results)); + request->num_scripts_done = request->scripts->len; + request_free(request); + return; + } + + nm_clear_g_source(&gl.quit_id); + + gl.num_requests_pending++; + + for (i = 0; i < request->scripts->len; i++) { + ScriptInfo *s = g_ptr_array_index(request->scripts, i); + + if (!s->wait) { + script_dispatch(s); + num_nowait++; + } + } + + if (num_nowait < request->scripts->len) { + /* The request has at least one wait script. + * Try next_request() to schedule the request for + * execution. This either enqueues the request or + * sets it as gl.current_request. */ + if (next_request(request)) { + /* @request is now @current_request. Go ahead and + * schedule the first wait script. */ + if (!dispatch_one_script(request)) { + /* If that fails, we might be already finished with the + * request. Try complete_request(). */ + complete_request(request); + + if (next_request(NULL)) { + /* As @request was successfully scheduled as next_request(), there is no + * other request in queue that can be scheduled afterwards. Assert against + * that, but call next_request() to clear current_request. */ + g_assert_not_reached(); + } + } + } + } else { + /* The request contains only no-wait scripts. Try to complete + * the request right away (we might have failed to schedule any + * of the scripts). It will be either completed now, or later + * when the pending scripts return. + * We don't enqueue it to gl.requests_waiting. + * There is no need to handle next_request(), because @request is + * not the current request anyway and does not interfere with requests + * that have any "wait" scripts. */ + complete_request(request); + } } static void -on_name_acquired (GDBusConnection *connection, - const char *name, - gpointer user_data) +on_name_acquired(GDBusConnection *connection, const char *name, gpointer user_data) { - gl.ever_acquired_name = TRUE; + gl.ever_acquired_name = TRUE; } static void -on_name_lost (GDBusConnection *connection, - const char *name, - gpointer user_data) +on_name_lost(GDBusConnection *connection, const char *name, gpointer user_data) { - if (!connection) { - if (!gl.ever_acquired_name) { - _LOG_X_W ("Could not get the system bus. Make sure the message bus daemon is running!"); - gl.exit_with_failure = TRUE; - } else { - _LOG_X_I ("System bus stopped. Exiting"); - } - } else if (!gl.ever_acquired_name) { - _LOG_X_W ("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service."); - gl.exit_with_failure = TRUE; - } else - _LOG_X_I ("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting"); - - g_main_loop_quit (gl.loop); + if (!connection) { + if (!gl.ever_acquired_name) { + _LOG_X_W("Could not get the system bus. Make sure the message bus daemon is running!"); + gl.exit_with_failure = TRUE; + } else { + _LOG_X_I("System bus stopped. Exiting"); + } + } else if (!gl.ever_acquired_name) { + _LOG_X_W("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service."); + gl.exit_with_failure = TRUE; + } else + _LOG_X_I("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting"); + + g_main_loop_quit(gl.loop); } 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) +_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 (nm_streq (interface_name, NM_DISPATCHER_DBUS_INTERFACE)) { - if (nm_streq (method_name, "Action")) { - _method_call_action (invocation, parameters); - return; - } - } - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); + if (nm_streq(interface_name, NM_DISPATCHER_DBUS_INTERFACE)) { + if (nm_streq(method_name, "Action")) { + _method_call_action(invocation, parameters); + return; + } + } + g_dbus_method_invocation_return_error(invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method %s", + method_name); } -static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO ( - NM_DISPATCHER_DBUS_INTERFACE, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_GDBUS_METHOD_INFO ( - "Action", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("action", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("connection_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("device_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("device_proxy_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("device_ip4_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("device_ip6_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("device_dhcp4_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("device_dhcp6_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("connectivity_state", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("vpn_ip_iface", "s"), - NM_DEFINE_GDBUS_ARG_INFO ("vpn_proxy_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("vpn_ip4_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("vpn_ip6_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO ("debug", "b"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("results", "a(sus)"), - ), - ), - ), -); +static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO( + NM_DISPATCHER_DBUS_INTERFACE, + .methods = NM_DEFINE_GDBUS_METHOD_INFOS( + NM_DEFINE_GDBUS_METHOD_INFO( + "Action", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("action", "s"), + NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), + NM_DEFINE_GDBUS_ARG_INFO("connection_properties", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("device_properties", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("device_proxy_properties", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("device_ip4_config", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("device_ip6_config", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("device_dhcp4_config", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("device_dhcp6_config", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("connectivity_state", "s"), + NM_DEFINE_GDBUS_ARG_INFO("vpn_ip_iface", "s"), + NM_DEFINE_GDBUS_ARG_INFO("vpn_proxy_properties", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("vpn_ip4_config", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("vpn_ip6_config", "a{sv}"), + NM_DEFINE_GDBUS_ARG_INFO("debug", "b"), ), + .out_args = + NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("results", "a(sus)"), ), ), ), ); static const GDBusInterfaceVTable interface_vtable = { - .method_call = _method_call, + .method_call = _method_call, }; /*****************************************************************************/ static void -log_handler (const char *log_domain, - GLogLevelFlags log_level, - const char *message, - gpointer ignored) +log_handler(const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer ignored) { - int syslog_priority; - - switch (log_level) { - case G_LOG_LEVEL_ERROR: - syslog_priority = LOG_CRIT; - break; - case G_LOG_LEVEL_CRITICAL: - syslog_priority = LOG_ERR; - break; - case G_LOG_LEVEL_WARNING: - syslog_priority = LOG_WARNING; - break; - case G_LOG_LEVEL_MESSAGE: - syslog_priority = LOG_NOTICE; - break; - case G_LOG_LEVEL_DEBUG: - syslog_priority = LOG_DEBUG; - break; - case G_LOG_LEVEL_INFO: - default: - syslog_priority = LOG_INFO; - break; - } - - syslog (syslog_priority, "%s", message); + int syslog_priority; + + switch (log_level) { + case G_LOG_LEVEL_ERROR: + syslog_priority = LOG_CRIT; + break; + case G_LOG_LEVEL_CRITICAL: + syslog_priority = LOG_ERR; + break; + case G_LOG_LEVEL_WARNING: + syslog_priority = LOG_WARNING; + break; + case G_LOG_LEVEL_MESSAGE: + syslog_priority = LOG_NOTICE; + break; + case G_LOG_LEVEL_DEBUG: + syslog_priority = LOG_DEBUG; + break; + case G_LOG_LEVEL_INFO: + default: + syslog_priority = LOG_INFO; + break; + } + + syslog(syslog_priority, "%s", message); } static void -logging_setup (void) +logging_setup(void) { - openlog (G_LOG_DOMAIN, LOG_CONS, LOG_DAEMON); - g_log_set_handler (G_LOG_DOMAIN, - G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, - log_handler, - NULL); + openlog(G_LOG_DOMAIN, LOG_CONS, LOG_DAEMON); + g_log_set_handler(G_LOG_DOMAIN, + G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, + log_handler, + NULL); } static void -logging_shutdown (void) +logging_shutdown(void) { - closelog (); + closelog(); } static gboolean -signal_handler (gpointer user_data) +signal_handler(gpointer user_data) { - int signo = GPOINTER_TO_INT (user_data); + int signo = GPOINTER_TO_INT(user_data); - _LOG_X_I ("Caught signal %d, shutting down...", signo); - g_main_loop_quit (gl.loop); + _LOG_X_I("Caught signal %d, shutting down...", signo); + g_main_loop_quit(gl.loop); - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } static gboolean -parse_command_line (int *p_argc, - char ***p_argv, - GError **error) +parse_command_line(int *p_argc, char ***p_argv, GError **error) { - GOptionContext *opt_ctx; - GOptionEntry entries[] = { - { "debug", 0, 0, G_OPTION_ARG_NONE, &gl.debug, "Output to console rather than syslog", NULL }, - { "persist", 0, 0, G_OPTION_ARG_NONE, &gl.persist, "Don't quit after a short timeout", NULL }, - { NULL } - }; - gboolean success; + GOptionContext *opt_ctx; + GOptionEntry entries[] = { + {"debug", 0, 0, G_OPTION_ARG_NONE, &gl.debug, "Output to console rather than syslog", NULL}, + {"persist", 0, 0, G_OPTION_ARG_NONE, &gl.persist, "Don't quit after a short timeout", NULL}, + {NULL}}; + gboolean success; - opt_ctx = g_option_context_new (NULL); - g_option_context_set_summary (opt_ctx, "Executes scripts upon actions by NetworkManager."); - g_option_context_add_main_entries (opt_ctx, entries, NULL); + opt_ctx = g_option_context_new(NULL); + g_option_context_set_summary(opt_ctx, "Executes scripts upon actions by NetworkManager."); + g_option_context_add_main_entries(opt_ctx, entries, NULL); - success = g_option_context_parse (opt_ctx, p_argc, p_argv, error); + success = g_option_context_parse(opt_ctx, p_argc, p_argv, error); - g_option_context_free (opt_ctx); + g_option_context_free(opt_ctx); - return success; + return success; } int -main (int argc, char **argv) +main(int argc, char **argv) { - gs_free_error GError *error = NULL; - guint signal_id_term = 0; - guint signal_id_int = 0; - guint dbus_regist_id = 0; - guint dbus_own_name_id = 0; - - if (!parse_command_line (&argc, &argv, &error)) { - _LOG_X_W ("Error parsing command line arguments: %s", error->message); - gl.exit_with_failure = TRUE; - goto done; - } - - signal_id_term = g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM)); - signal_id_int = g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT)); - - if (gl.debug) { - if (!g_getenv ("G_MESSAGES_DEBUG")) { - /* we log our regular messages using g_debug() and g_info(). - * When we redirect glib logging to syslog, there is no problem. - * But in "debug" mode, glib will no print these messages unless - * we set G_MESSAGES_DEBUG. */ - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - } - } else - logging_setup (); - - gl.loop = g_main_loop_new (NULL, FALSE); - - gl.dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (!gl.dbus_connection) { - _LOG_X_W ("Could not get the system bus (%s). Make sure the message bus daemon is running!", - error->message); - gl.exit_with_failure = TRUE; - goto done; - } - - gl.requests_waiting = g_queue_new (); - - dbus_regist_id = g_dbus_connection_register_object (gl.dbus_connection, - NM_DISPATCHER_DBUS_PATH, - interface_info, - NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable), - NULL, - NULL, - &error); - if (dbus_regist_id == 0) { - _LOG_X_W ("Could not export Dispatcher D-Bus interface: %s", error->message); - gl.exit_with_failure = 1; - goto done; - } - - dbus_own_name_id = g_bus_own_name_on_connection (gl.dbus_connection, - NM_DISPATCHER_DBUS_SERVICE, - G_BUS_NAME_OWNER_FLAGS_NONE, - on_name_acquired, - on_name_lost, - NULL, NULL); - - quit_timeout_reschedule (); - - g_main_loop_run (gl.loop); + gs_free_error GError *error = NULL; + guint signal_id_term = 0; + guint signal_id_int = 0; + guint dbus_regist_id = 0; + guint dbus_own_name_id = 0; + + if (!parse_command_line(&argc, &argv, &error)) { + _LOG_X_W("Error parsing command line arguments: %s", error->message); + gl.exit_with_failure = TRUE; + goto done; + } + + signal_id_term = g_unix_signal_add(SIGTERM, signal_handler, GINT_TO_POINTER(SIGTERM)); + signal_id_int = g_unix_signal_add(SIGINT, signal_handler, GINT_TO_POINTER(SIGINT)); + + if (gl.debug) { + if (!g_getenv("G_MESSAGES_DEBUG")) { + /* we log our regular messages using g_debug() and g_info(). + * When we redirect glib logging to syslog, there is no problem. + * But in "debug" mode, glib will no print these messages unless + * we set G_MESSAGES_DEBUG. */ + g_setenv("G_MESSAGES_DEBUG", "all", TRUE); + } + } else + logging_setup(); + + gl.loop = g_main_loop_new(NULL, FALSE); + + gl.dbus_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!gl.dbus_connection) { + _LOG_X_W("Could not get the system bus (%s). Make sure the message bus daemon is running!", + error->message); + gl.exit_with_failure = TRUE; + goto done; + } + + gl.requests_waiting = g_queue_new(); + + dbus_regist_id = + g_dbus_connection_register_object(gl.dbus_connection, + NM_DISPATCHER_DBUS_PATH, + interface_info, + NM_UNCONST_PTR(GDBusInterfaceVTable, &interface_vtable), + NULL, + NULL, + &error); + if (dbus_regist_id == 0) { + _LOG_X_W("Could not export Dispatcher D-Bus interface: %s", error->message); + gl.exit_with_failure = 1; + goto done; + } + + dbus_own_name_id = g_bus_own_name_on_connection(gl.dbus_connection, + NM_DISPATCHER_DBUS_SERVICE, + G_BUS_NAME_OWNER_FLAGS_NONE, + on_name_acquired, + on_name_lost, + NULL, + NULL); + + quit_timeout_reschedule(); + + g_main_loop_run(gl.loop); done: - if (gl.num_requests_pending > 0) { - /* this only happens when we quit due to SIGTERM (not due to the idle timer). - * - * Log a warning about pending scripts. - * - * Maybe we should notify NetworkManager that these scripts are left in an unknown state. - * But this is either a bug of a dispatcher script (not terminating in time). - * - * FIXME(shutdown): Also, currently NetworkManager behaves wrongly on shutdown. - * Note that systemd would not terminate NetworkManager-dispatcher before NetworkManager. - * It's NetworkManager's responsibility to keep running long enough so that all requests - * can complete (with a watchdog timer, and a warning that user provided scripts hang). */ - _LOG_X_W ("exiting but there are still %u requests pending", gl.num_requests_pending); - } - - if (dbus_own_name_id != 0) - g_bus_unown_name (nm_steal_int (&dbus_own_name_id)); - - if (dbus_regist_id != 0) - g_dbus_connection_unregister_object (gl.dbus_connection, nm_steal_int (&dbus_regist_id)); - - nm_clear_pointer (&gl.requests_waiting, g_queue_free); - - nm_clear_g_source (&signal_id_term); - nm_clear_g_source (&signal_id_int); - nm_clear_g_source (&gl.quit_id); - nm_clear_pointer (&gl.loop, g_main_loop_unref); - g_clear_object (&gl.dbus_connection); - - if (!gl.debug) - logging_shutdown (); - - return gl.exit_with_failure ? 1 : 0; + if (gl.num_requests_pending > 0) { + /* this only happens when we quit due to SIGTERM (not due to the idle timer). + * + * Log a warning about pending scripts. + * + * Maybe we should notify NetworkManager that these scripts are left in an unknown state. + * But this is either a bug of a dispatcher script (not terminating in time). + * + * FIXME(shutdown): Also, currently NetworkManager behaves wrongly on shutdown. + * Note that systemd would not terminate NetworkManager-dispatcher before NetworkManager. + * It's NetworkManager's responsibility to keep running long enough so that all requests + * can complete (with a watchdog timer, and a warning that user provided scripts hang). */ + _LOG_X_W("exiting but there are still %u requests pending", gl.num_requests_pending); + } + + if (dbus_own_name_id != 0) + g_bus_unown_name(nm_steal_int(&dbus_own_name_id)); + + if (dbus_regist_id != 0) + g_dbus_connection_unregister_object(gl.dbus_connection, nm_steal_int(&dbus_regist_id)); + + nm_clear_pointer(&gl.requests_waiting, g_queue_free); + + nm_clear_g_source(&signal_id_term); + nm_clear_g_source(&signal_id_int); + nm_clear_g_source(&gl.quit_id); + nm_clear_pointer(&gl.loop, g_main_loop_unref); + g_clear_object(&gl.dbus_connection); + + if (!gl.debug) + logging_shutdown(); + + return gl.exit_with_failure ? 1 : 0; } |