mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-31 20:20:32 +01:00
merge: branch 'bg/resolve-helper'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/877
This commit is contained in:
commit
a68b63a859
22 changed files with 799 additions and 63 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -427,6 +427,7 @@ test-*.trs
|
|||
/src/initrd/tests/test-ibft-reader
|
||||
/src/ndisc/tests/test-ndisc-fake
|
||||
/src/ndisc/tests/test-ndisc-linux
|
||||
/src/nm-daemon-helper/nm-daemon-helper
|
||||
/src/nm-iface-helper
|
||||
/src/platform/tests/dump
|
||||
/src/platform/tests/monitor
|
||||
|
|
|
|||
25
Makefile.am
25
Makefile.am
|
|
@ -4598,6 +4598,31 @@ EXTRA_DIST += \
|
|||
src/nm-dispatcher/tests/meson.build \
|
||||
$(NULL)
|
||||
|
||||
###############################################################################
|
||||
# src/nm-daemon-helper
|
||||
###############################################################################
|
||||
|
||||
libexec_PROGRAMS += src/nm-daemon-helper/nm-daemon-helper
|
||||
|
||||
src_nm_daemon_helper_nm_daemon_helper_CPPFLAGS = \
|
||||
$(dflt_cppflags) \
|
||||
-I$(srcdir)/src \
|
||||
-I$(builddir)/src \
|
||||
$(NULL)
|
||||
|
||||
src_nm_daemon_helper_nm_daemon_helper_LDFLAGS = \
|
||||
-Wl,--version-script="$(srcdir)/linker-script-binary.ver" \
|
||||
$(SANITIZER_EXEC_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
src_nm_daemon_helper_nm_daemon_helper_LDADD = \
|
||||
src/libnm-std-aux/libnm-std-aux.la \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST += \
|
||||
src/nm-daemon-helper/meson.build \
|
||||
$(NULL)
|
||||
|
||||
###############################################################################
|
||||
# src/nm-online
|
||||
###############################################################################
|
||||
|
|
|
|||
|
|
@ -998,6 +998,7 @@ fi
|
|||
%{_libexecdir}/nm-dispatcher
|
||||
%{_libexecdir}/nm-iface-helper
|
||||
%{_libexecdir}/nm-initrd-generator
|
||||
%{_libexecdir}/nm-daemon-helper
|
||||
%dir %{_libdir}/%{name}
|
||||
%dir %{nmplugindir}
|
||||
%{nmplugindir}/libnm-settings-plugin*.so
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "src/core/nm-default-daemon.h"
|
||||
#include "src/core/dns/nm-dns-manager.h"
|
||||
#include "src/core/dns/nm-dns-systemd-resolved.h"
|
||||
|
||||
#include "nm-device-utils.h"
|
||||
#include "nm-core-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -152,3 +155,202 @@ NM_UTILS_LOOKUP_STR_DEFINE(nm_device_ip_state_to_str,
|
|||
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_CONF, "conf"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_DONE, "done"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_FAIL, "fail"), );
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define SD_RESOLVED_DNS (1UL << 0)
|
||||
/* Don't answer request from locally synthesized records (which includes /etc/hosts) */
|
||||
#define SD_RESOLVED_NO_SYNTHESIZE (1UL << 11)
|
||||
|
||||
typedef struct {
|
||||
int addr_family;
|
||||
NMIPAddr address;
|
||||
gulong cancellable_id;
|
||||
GTask * task;
|
||||
NMDnsSystemdResolvedResolveHandle *resolved_handle;
|
||||
} ResolveAddrInfo;
|
||||
|
||||
#define _NMLOG_PREFIX_NAME "resolve-addr"
|
||||
#define _NMLOG_DOMAIN LOGD_CORE
|
||||
#define _NMLOG2(level, info, ...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \
|
||||
ResolveAddrInfo *_info = (info); \
|
||||
char _addr_str[NM_UTILS_INET_ADDRSTRLEN]; \
|
||||
\
|
||||
_nm_log((level), \
|
||||
(_NMLOG_DOMAIN), \
|
||||
0, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
_NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \
|
||||
",%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
NM_HASH_OBFUSCATE_PTR(_info), \
|
||||
nm_utils_inet_ntop(_info->addr_family, &_info->address, _addr_str) \
|
||||
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
static void
|
||||
resolve_addr_info_free(ResolveAddrInfo *info)
|
||||
{
|
||||
nm_assert(info->cancellable_id == 0);
|
||||
nm_assert(!info->resolved_handle);
|
||||
g_object_unref(info->task);
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_addr_complete(ResolveAddrInfo *info, char *hostname_take, GError *error_take)
|
||||
{
|
||||
nm_assert(!!hostname_take != !!error_take);
|
||||
|
||||
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id);
|
||||
if (error_take)
|
||||
g_task_return_error(info->task, error_take);
|
||||
else
|
||||
g_task_return_pointer(info->task, hostname_take, g_free);
|
||||
|
||||
resolve_addr_info_free(info);
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
ResolveAddrInfo *info = user_data;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_free char * output = NULL;
|
||||
|
||||
output = nm_utils_spawn_helper_finish(result, &error);
|
||||
if (nm_utils_error_is_cancelled(error))
|
||||
return;
|
||||
|
||||
_LOG2D(info, "helper returned hostname '%s'", output);
|
||||
|
||||
resolve_addr_complete(info, g_steal_pointer(&output), g_steal_pointer(&error));
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_addr_spawn_helper(ResolveAddrInfo *info)
|
||||
{
|
||||
char addr_str[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
nm_utils_inet_ntop(info->addr_family, &info->address, addr_str);
|
||||
_LOG2D(info, "start lookup via nm-daemon-helper");
|
||||
nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str),
|
||||
g_task_get_cancellable(info->task),
|
||||
resolve_addr_helper_cb,
|
||||
info);
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_addr_resolved_cb(NMDnsSystemdResolved * resolved,
|
||||
NMDnsSystemdResolvedResolveHandle * handle,
|
||||
const NMDnsSystemdResolvedAddressResult *names,
|
||||
guint names_len,
|
||||
guint64 flags,
|
||||
GError * error,
|
||||
gpointer user_data)
|
||||
{
|
||||
ResolveAddrInfo *info = user_data;
|
||||
|
||||
info->resolved_handle = NULL;
|
||||
|
||||
if (nm_utils_error_is_cancelled(error))
|
||||
return;
|
||||
|
||||
if (error) {
|
||||
gs_free char *dbus_error = NULL;
|
||||
|
||||
_LOG2D(info, "error resolving via systemd-resolved: %s", error->message);
|
||||
|
||||
dbus_error = g_dbus_error_get_remote_error(error);
|
||||
if (nm_streq0(dbus_error, "org.freedesktop.resolve1.DnsError.NXDOMAIN")) {
|
||||
resolve_addr_complete(info, NULL, g_error_copy(error));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve_addr_spawn_helper(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (names_len == 0) {
|
||||
_LOG2D(info, "systemd-resolved returned no result");
|
||||
resolve_addr_complete(info, g_strdup(""), NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
_LOG2D(info, "systemd-resolved returned hostname '%s'", names[0].name);
|
||||
resolve_addr_complete(info, g_strdup(names[0].name), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
resolve_addr_cancelled(GObject *object, gpointer user_data)
|
||||
{
|
||||
ResolveAddrInfo *info = user_data;
|
||||
GError * error = NULL;
|
||||
|
||||
nm_clear_g_signal_handler(g_task_get_cancellable(info->task), &info->cancellable_id);
|
||||
nm_clear_pointer(&info->resolved_handle, nm_dns_systemd_resolved_resolve_cancel);
|
||||
nm_utils_error_set_cancelled(&error, FALSE, NULL);
|
||||
resolve_addr_complete(info, NULL, error);
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_resolve_address(int addr_family,
|
||||
gconstpointer address,
|
||||
GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data)
|
||||
{
|
||||
ResolveAddrInfo * info;
|
||||
NMDnsSystemdResolved *resolved;
|
||||
|
||||
info = g_new(ResolveAddrInfo, 1);
|
||||
*info = (ResolveAddrInfo){
|
||||
.task = nm_g_task_new(NULL, cancellable, nm_device_resolve_address, callback, cb_data),
|
||||
.addr_family = addr_family,
|
||||
.address = nm_ip_addr_init(addr_family, address),
|
||||
};
|
||||
|
||||
if (cancellable) {
|
||||
gulong signal_id;
|
||||
|
||||
signal_id =
|
||||
g_cancellable_connect(cancellable, G_CALLBACK(resolve_addr_cancelled), info, NULL);
|
||||
if (signal_id == 0) {
|
||||
/* the request is already cancelled. Return. */
|
||||
return;
|
||||
}
|
||||
info->cancellable_id = signal_id;
|
||||
}
|
||||
|
||||
resolved = (NMDnsSystemdResolved *) nm_dns_manager_get_systemd_resolved(nm_dns_manager_get());
|
||||
if (resolved) {
|
||||
_LOG2D(info, "start lookup via systemd-resolved");
|
||||
info->resolved_handle =
|
||||
nm_dns_systemd_resolved_resolve_address(resolved,
|
||||
0,
|
||||
addr_family,
|
||||
address,
|
||||
SD_RESOLVED_DNS | SD_RESOLVED_NO_SYNTHESIZE,
|
||||
20000,
|
||||
resolve_addr_resolved_cb,
|
||||
info);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve_addr_spawn_helper(info);
|
||||
}
|
||||
|
||||
char *
|
||||
nm_device_resolve_address_finish(GAsyncResult *result, GError **error)
|
||||
{
|
||||
GTask *task = G_TASK(result);
|
||||
|
||||
nm_assert(nm_g_task_is_valid(result, NULL, nm_device_resolve_address));
|
||||
|
||||
return g_task_propagate_pointer(task, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,4 +85,14 @@ const char *nm_device_ip_state_to_str(NMDeviceIPState ip_state);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void nm_device_resolve_address(int addr_family,
|
||||
gconstpointer address,
|
||||
GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data);
|
||||
|
||||
char *nm_device_resolve_address_finish(GAsyncResult *result, GError **error);
|
||||
|
||||
#endif /* __DEVICES_NM_DEVICE_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
#include "nm-audit-manager.h"
|
||||
#include "nm-connectivity.h"
|
||||
#include "nm-dbus-interface.h"
|
||||
#include "nm-hostname-manager.h"
|
||||
|
||||
#include "nm-device-generic.h"
|
||||
#include "nm-device-vlan.h"
|
||||
|
|
@ -220,7 +221,6 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
ResolverState state;
|
||||
GResolver * resolver;
|
||||
GInetAddress *address;
|
||||
GCancellable *cancellable;
|
||||
char * hostname;
|
||||
|
|
@ -777,7 +777,6 @@ _hostname_resolver_free(HostnameResolver *resolver)
|
|||
|
||||
nm_clear_g_source(&resolver->timeout_id);
|
||||
nm_clear_g_cancellable(&resolver->cancellable);
|
||||
nm_g_object_unref(resolver->resolver);
|
||||
nm_g_object_unref(resolver->address);
|
||||
g_free(resolver->hostname);
|
||||
nm_g_slice_free(resolver);
|
||||
|
|
@ -17666,21 +17665,37 @@ hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer use
|
|||
NMDevice * self;
|
||||
gs_free char * hostname = NULL;
|
||||
gs_free char * addr_str = NULL;
|
||||
gs_free char * output = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
hostname = g_resolver_lookup_by_address_finish(G_RESOLVER(source), result, &error);
|
||||
output = nm_device_resolve_address_finish(result, &error);
|
||||
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
resolver = user_data;
|
||||
self = resolver->device;
|
||||
resolver->state = RESOLVER_DONE;
|
||||
resolver->hostname = g_strdup(hostname);
|
||||
resolver = user_data;
|
||||
self = resolver->device;
|
||||
resolver->state = RESOLVER_DONE;
|
||||
|
||||
_LOGD(LOGD_DNS,
|
||||
"hostname-from-dns: lookup done for %s, result %s%s%s",
|
||||
(addr_str = g_inet_address_to_string(resolver->address)),
|
||||
NM_PRINT_FMT_QUOTE_STRING(hostname));
|
||||
if (error) {
|
||||
_LOGD(LOGD_DNS,
|
||||
"hostname-from-dns: lookup error for %s: %s",
|
||||
(addr_str = g_inet_address_to_string(resolver->address)),
|
||||
error->message);
|
||||
} else {
|
||||
gboolean valid;
|
||||
|
||||
resolver->hostname = g_steal_pointer(&output);
|
||||
valid = nm_hostname_manager_validate_hostname(resolver->hostname);
|
||||
|
||||
_LOGD(LOGD_DNS,
|
||||
"hostname-from-dns: lookup done for %s, result %s%s%s%s",
|
||||
(addr_str = g_inet_address_to_string(resolver->address)),
|
||||
NM_PRINT_FMT_QUOTE_STRING(resolver->hostname),
|
||||
valid ? "" : " (invalid)");
|
||||
|
||||
if (!valid)
|
||||
g_clear_pointer(&resolver->hostname, g_free);
|
||||
}
|
||||
|
||||
nm_clear_g_cancellable(&resolver->cancellable);
|
||||
g_signal_emit(self, signals[DNS_LOOKUP_DONE], 0);
|
||||
|
|
@ -17778,7 +17793,6 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean
|
|||
if (!resolver) {
|
||||
resolver = g_slice_new(HostnameResolver);
|
||||
*resolver = (HostnameResolver){
|
||||
.resolver = g_resolver_get_default(),
|
||||
.device = self,
|
||||
.addr_family = addr_family,
|
||||
.state = RESOLVER_WAIT_ADDRESS,
|
||||
|
|
@ -17828,20 +17842,15 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean
|
|||
}
|
||||
|
||||
if (address_changed && new_address) {
|
||||
gs_free char *str = NULL;
|
||||
|
||||
_LOGT(LOGD_DNS,
|
||||
"hostname-from-dns: starting lookup for address %s",
|
||||
(str = g_inet_address_to_string(new_address)));
|
||||
|
||||
resolver->state = RESOLVER_IN_PROGRESS;
|
||||
resolver->cancellable = g_cancellable_new();
|
||||
resolver->address = g_steal_pointer(&new_address);
|
||||
g_resolver_lookup_by_address_async(resolver->resolver,
|
||||
resolver->address,
|
||||
resolver->cancellable,
|
||||
hostname_dns_lookup_callback,
|
||||
resolver);
|
||||
|
||||
nm_device_resolve_address(addr_family,
|
||||
g_inet_address_to_bytes(resolver->address),
|
||||
resolver->cancellable,
|
||||
hostname_dns_lookup_callback,
|
||||
resolver);
|
||||
nm_clear_g_source(&resolver->timeout_id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -517,20 +517,12 @@ daemon_watch_cb(GPid pid, int status, gpointer user_data)
|
|||
{
|
||||
NMDhcpClient * self = NM_DHCP_CLIENT(user_data);
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
gs_free char * desc = NULL;
|
||||
|
||||
g_return_if_fail(priv->watch_id);
|
||||
priv->watch_id = 0;
|
||||
|
||||
if (WIFEXITED(status))
|
||||
_LOGI("client pid %d exited with status %d", pid, WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
_LOGI("client pid %d killed by signal %d", pid, WTERMSIG(status));
|
||||
else if (WIFSTOPPED(status))
|
||||
_LOGI("client pid %d stopped by signal %d", pid, WSTOPSIG(status));
|
||||
else if (WIFCONTINUED(status))
|
||||
_LOGI("client pid %d resumed (by SIGCONT)", pid);
|
||||
else
|
||||
_LOGW("client died abnormally");
|
||||
_LOGI("client pid %d %s", pid, (desc = nm_utils_get_process_exit_status_desc(status)));
|
||||
|
||||
priv->pid = -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#define __NETWORKMANAGER_DNS_DNSMASQ_H__
|
||||
|
||||
#include "nm-dns-plugin.h"
|
||||
#include "nm-dns-manager.h"
|
||||
|
||||
#define NM_TYPE_DNS_DNSMASQ (nm_dns_dnsmasq_get_type())
|
||||
#define NM_DNS_DNSMASQ(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasq))
|
||||
|
|
|
|||
|
|
@ -378,11 +378,11 @@ _mgr_get_configs_lst_head(NMDnsManager *self)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
nm_dns_manager_has_systemd_resolved(NMDnsManager *self)
|
||||
NMDnsPlugin *
|
||||
nm_dns_manager_get_systemd_resolved(NMDnsManager *self)
|
||||
{
|
||||
NMDnsManagerPrivate * priv;
|
||||
NMDnsSystemdResolved *plugin = NULL;
|
||||
NMDnsManagerPrivate *priv;
|
||||
NMDnsPlugin * plugin = NULL;
|
||||
|
||||
g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE);
|
||||
|
||||
|
|
@ -390,11 +390,14 @@ nm_dns_manager_has_systemd_resolved(NMDnsManager *self)
|
|||
|
||||
if (priv->sd_resolve_plugin) {
|
||||
nm_assert(!NM_IS_DNS_SYSTEMD_RESOLVED(priv->plugin));
|
||||
plugin = NM_DNS_SYSTEMD_RESOLVED(priv->sd_resolve_plugin);
|
||||
plugin = priv->sd_resolve_plugin;
|
||||
} else if (NM_IS_DNS_SYSTEMD_RESOLVED(priv->plugin))
|
||||
plugin = NM_DNS_SYSTEMD_RESOLVED(priv->plugin);
|
||||
plugin = priv->plugin;
|
||||
|
||||
return plugin && nm_dns_systemd_resolved_is_running(plugin);
|
||||
if (plugin && nm_dns_systemd_resolved_is_running(NM_DNS_SYSTEMD_RESOLVED(plugin)))
|
||||
return plugin;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "nm-ip4-config.h"
|
||||
#include "nm-ip6-config.h"
|
||||
#include "nm-setting-connection.h"
|
||||
#include "nm-dns-plugin.h"
|
||||
|
||||
typedef enum {
|
||||
NM_DNS_IP_CONFIG_TYPE_REMOVED = -1,
|
||||
|
|
@ -148,7 +149,7 @@ typedef enum {
|
|||
|
||||
void nm_dns_manager_stop(NMDnsManager *self);
|
||||
|
||||
gboolean nm_dns_manager_has_systemd_resolved(NMDnsManager *self);
|
||||
NMDnsPlugin *nm_dns_manager_get_systemd_resolved(NMDnsManager *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
#ifndef __NM_DNS_PLUGIN_H__
|
||||
#define __NM_DNS_PLUGIN_H__
|
||||
|
||||
#include "nm-dns-manager.h"
|
||||
#include "c-list/src/c-list.h"
|
||||
|
||||
#include "nm-config-data.h"
|
||||
|
||||
#define NM_TYPE_DNS_PLUGIN (nm_dns_plugin_get_type())
|
||||
|
|
|
|||
|
|
@ -767,7 +767,7 @@ _resolve_handle_call_cb(GObject *source, GAsyncResult *result, gpointer user_dat
|
|||
|
||||
n = nm_g_array_append_new(v_names, NMDnsSystemdResolvedAddressResult);
|
||||
*n = (NMDnsSystemdResolvedAddressResult){
|
||||
.name = g_strdup(v_name),
|
||||
.name = g_steal_pointer(&v_name),
|
||||
.ifindex = v_ifindex,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__
|
||||
|
||||
#include "nm-dns-plugin.h"
|
||||
#include "nm-dns-manager.h"
|
||||
|
||||
#define NM_TYPE_DNS_SYSTEMD_RESOLVED (nm_dns_systemd_resolved_get_type())
|
||||
#define NM_DNS_SYSTEMD_RESOLVED(obj) \
|
||||
|
|
|
|||
|
|
@ -904,7 +904,7 @@ nm_connectivity_check_start(NMConnectivity * self,
|
|||
* This is relatively cumbersome to avoid, because we would have to go through
|
||||
* NMDnsSystemdResolved trying to asynchronously start the service, to ensure there
|
||||
* is only one attempt to start the service. */
|
||||
has_systemd_resolved = nm_dns_manager_has_systemd_resolved(nm_dns_manager_get());
|
||||
has_systemd_resolved = !!nm_dns_manager_get_systemd_resolved(nm_dns_manager_get());
|
||||
|
||||
if (has_systemd_resolved) {
|
||||
GDBusConnection *dbus_connection;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "libnm-glib-aux/nm-io-utils.h"
|
||||
#include "libnm-glib-aux/nm-secret-utils.h"
|
||||
#include "libnm-glib-aux/nm-time-utils.h"
|
||||
#include "libnm-glib-aux/nm-str-buf.h"
|
||||
#include "nm-utils.h"
|
||||
#include "libnm-core-intern/nm-core-internal.h"
|
||||
#include "nm-setting-connection.h"
|
||||
|
|
@ -4656,3 +4657,323 @@ NM_UTILS_LOOKUP_STR_DEFINE(nm_activation_type_to_string,
|
|||
NM_UTILS_LOOKUP_STR_ITEM(NM_ACTIVATION_TYPE_MANAGED, "managed"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM(NM_ACTIVATION_TYPE_ASSUME, "assume"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM(NM_ACTIVATION_TYPE_EXTERNAL, "external"), );
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
GPid pid;
|
||||
GTask * task;
|
||||
gulong cancellable_id;
|
||||
GSource *child_watch_source;
|
||||
GSource *timeout_source;
|
||||
|
||||
int child_stdin;
|
||||
int child_stdout;
|
||||
GSource *input_source;
|
||||
GSource *output_source;
|
||||
|
||||
NMStrBuf in_buffer;
|
||||
NMStrBuf out_buffer;
|
||||
gsize out_buffer_offset;
|
||||
} HelperInfo;
|
||||
|
||||
#define _NMLOG_PREFIX_NAME "helper"
|
||||
#define _NMLOG_DOMAIN LOGD_CORE
|
||||
#define _NMLOG2(level, info, ...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \
|
||||
HelperInfo *_info = (info); \
|
||||
\
|
||||
_nm_log((level), \
|
||||
(_NMLOG_DOMAIN), \
|
||||
0, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
_NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \
|
||||
",%d]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
NM_HASH_OBFUSCATE_PTR(_info), \
|
||||
_info->pid _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
static void
|
||||
helper_info_free(gpointer data)
|
||||
{
|
||||
HelperInfo *info = data;
|
||||
|
||||
nm_clear_g_source_inst(&info->child_watch_source);
|
||||
nm_clear_g_source_inst(&info->timeout_source);
|
||||
g_object_unref(info->task);
|
||||
|
||||
nm_str_buf_destroy(&info->in_buffer);
|
||||
nm_str_buf_destroy(&info->out_buffer);
|
||||
nm_clear_g_source_inst(&info->input_source);
|
||||
nm_clear_g_source_inst(&info->output_source);
|
||||
|
||||
if (info->child_stdout != -1)
|
||||
nm_close(info->child_stdout);
|
||||
if (info->child_stdin != -1)
|
||||
nm_close(info->child_stdin);
|
||||
|
||||
if (info->pid != -1) {
|
||||
nm_assert(info->pid > 1);
|
||||
nm_utils_kill_child_async(info->pid, SIGKILL, LOGD_CORE, _NMLOG_PREFIX_NAME, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
static void
|
||||
helper_complete(HelperInfo *info, GError *error)
|
||||
{
|
||||
if (error) {
|
||||
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task),
|
||||
&info->cancellable_id);
|
||||
g_task_return_error(info->task, error);
|
||||
helper_info_free(info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->input_source || info->output_source || info->pid != -1) {
|
||||
/* Wait that pipes are closed and process has terminated */
|
||||
return;
|
||||
}
|
||||
|
||||
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id);
|
||||
g_task_return_pointer(info->task, nm_str_buf_finalize(&info->in_buffer, NULL), g_free);
|
||||
helper_info_free(info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
helper_can_write(int fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
HelperInfo *info = user_data;
|
||||
gssize n_written;
|
||||
int errsv;
|
||||
|
||||
if (NM_FLAGS_HAS(condition, G_IO_ERR)) {
|
||||
errsv = EIO;
|
||||
goto out_error;
|
||||
} else if (NM_FLAGS_HAS(condition, G_IO_HUP)) {
|
||||
errsv = EPIPE;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
n_written = write(info->child_stdin,
|
||||
&((nm_str_buf_get_str_unsafe(&info->out_buffer))[info->out_buffer_offset]),
|
||||
info->out_buffer.len - info->out_buffer_offset);
|
||||
errsv = errno;
|
||||
|
||||
if (n_written < 0 && errsv != EAGAIN)
|
||||
goto out_error;
|
||||
|
||||
if (n_written > 0) {
|
||||
if ((gsize) n_written >= (info->out_buffer.len - info->out_buffer_offset)) {
|
||||
nm_assert((gsize) n_written == (info->out_buffer.len - info->out_buffer_offset));
|
||||
nm_clear_g_source_inst(&info->output_source);
|
||||
nm_close(info->child_stdin);
|
||||
info->child_stdin = -1;
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
info->out_buffer_offset += (gsize) n_written;
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
out_error:
|
||||
nm_clear_g_source_inst(&info->output_source);
|
||||
helper_complete(info,
|
||||
g_error_new(NM_UTILS_ERROR,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"error writing to helper: %d (%s)",
|
||||
errsv,
|
||||
nm_strerror_native(errsv)));
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
helper_have_data(int fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
HelperInfo *info = user_data;
|
||||
gssize n_read;
|
||||
GError * error = NULL;
|
||||
|
||||
n_read = nm_utils_fd_read(fd, &info->in_buffer);
|
||||
_LOG2T(info, "read returns %ld", (long) n_read);
|
||||
|
||||
if (n_read > 0)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
nm_clear_g_source_inst(&info->input_source);
|
||||
nm_close(info->child_stdout);
|
||||
info->child_stdout = -1;
|
||||
|
||||
_LOG2T(info, "stdout closed");
|
||||
|
||||
if (n_read < 0) {
|
||||
error = g_error_new(NM_UTILS_ERROR,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"read from process returned %d (%s)",
|
||||
(int) -n_read,
|
||||
nm_strerror_native((int) -n_read));
|
||||
}
|
||||
|
||||
helper_complete(info, error);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
helper_child_terminated(GPid pid, int status, gpointer user_data)
|
||||
{
|
||||
HelperInfo * info = user_data;
|
||||
GError * error = NULL;
|
||||
gs_free char *status_desc = NULL;
|
||||
|
||||
_LOG2D(info, "process %s", (status_desc = nm_utils_get_process_exit_status_desc(status)));
|
||||
|
||||
info->pid = -1;
|
||||
nm_clear_g_source_inst(&info->child_watch_source);
|
||||
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
if (!status_desc)
|
||||
status_desc = nm_utils_get_process_exit_status_desc(status);
|
||||
error =
|
||||
g_error_new(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "helper process %s", status_desc);
|
||||
}
|
||||
|
||||
helper_complete(info, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
helper_timeout(gpointer user_data)
|
||||
{
|
||||
HelperInfo *info = user_data;
|
||||
|
||||
nm_clear_g_source_inst(&info->timeout_source);
|
||||
helper_complete(info, g_error_new_literal(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "timed out"));
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
helper_cancelled(GObject *object, gpointer user_data)
|
||||
{
|
||||
HelperInfo *info = user_data;
|
||||
GError * error = NULL;
|
||||
|
||||
nm_clear_g_signal_handler(g_task_get_cancellable(info->task), &info->cancellable_id);
|
||||
nm_utils_error_set_cancelled(&error, FALSE, NULL);
|
||||
helper_complete(info, error);
|
||||
}
|
||||
|
||||
void
|
||||
nm_utils_spawn_helper(const char *const * args,
|
||||
GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data)
|
||||
{
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_free char * commands = NULL;
|
||||
HelperInfo * info;
|
||||
int fd_flags;
|
||||
const char *const * arg;
|
||||
|
||||
nm_assert(args && args[0]);
|
||||
|
||||
info = g_new(HelperInfo, 1);
|
||||
*info = (HelperInfo){
|
||||
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
|
||||
.child_stdin = -1,
|
||||
.child_stdout = -1,
|
||||
.pid = -1,
|
||||
};
|
||||
|
||||
if (!g_spawn_async_with_pipes("/",
|
||||
(char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"),
|
||||
(char **) NM_MAKE_STRV(),
|
||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL,
|
||||
NULL,
|
||||
&info->pid,
|
||||
&info->child_stdin,
|
||||
&info->child_stdout,
|
||||
NULL,
|
||||
&error)) {
|
||||
info->child_stdin = -1;
|
||||
info->child_stdout = -1;
|
||||
info->pid = -1;
|
||||
g_task_return_error(info->task,
|
||||
g_error_new(NM_UTILS_ERROR,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"error spawning nm-helper: %s",
|
||||
error->message));
|
||||
helper_info_free(info);
|
||||
return;
|
||||
}
|
||||
|
||||
_LOG2D(info, "spawned process with args: %s", (commands = g_strjoinv(" ", (char **) args)));
|
||||
|
||||
info->child_watch_source = g_child_watch_source_new(info->pid);
|
||||
g_source_set_callback(info->child_watch_source,
|
||||
G_SOURCE_FUNC(helper_child_terminated),
|
||||
info,
|
||||
NULL);
|
||||
g_source_attach(info->child_watch_source, g_main_context_get_thread_default());
|
||||
|
||||
info->timeout_source =
|
||||
nm_g_timeout_source_new_seconds(20, G_PRIORITY_DEFAULT, helper_timeout, info, NULL);
|
||||
g_source_attach(info->timeout_source, g_main_context_get_thread_default());
|
||||
|
||||
/* Set file descriptors as non-blocking */
|
||||
fd_flags = fcntl(info->child_stdin, F_GETFD, 0);
|
||||
fcntl(info->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
fd_flags = fcntl(info->child_stdout, F_GETFD, 0);
|
||||
fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
|
||||
|
||||
/* Watch process stdin */
|
||||
nm_str_buf_init(&info->out_buffer, 32, TRUE);
|
||||
for (arg = args; *arg; arg++) {
|
||||
nm_str_buf_append(&info->out_buffer, *arg);
|
||||
nm_str_buf_append_c(&info->out_buffer, '\0');
|
||||
}
|
||||
info->output_source = nm_g_unix_fd_source_new(info->child_stdin,
|
||||
G_IO_OUT | G_IO_ERR | G_IO_HUP,
|
||||
G_PRIORITY_DEFAULT,
|
||||
helper_can_write,
|
||||
info,
|
||||
NULL);
|
||||
g_source_attach(info->output_source, g_main_context_get_thread_default());
|
||||
|
||||
/* Watch process stdout */
|
||||
nm_str_buf_init(&info->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
|
||||
info->input_source = nm_g_unix_fd_source_new(info->child_stdout,
|
||||
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||||
G_PRIORITY_DEFAULT,
|
||||
helper_have_data,
|
||||
info,
|
||||
NULL);
|
||||
g_source_attach(info->input_source, g_main_context_get_thread_default());
|
||||
|
||||
if (cancellable) {
|
||||
gulong signal_id;
|
||||
|
||||
signal_id = g_cancellable_connect(cancellable, G_CALLBACK(helper_cancelled), info, NULL);
|
||||
if (signal_id == 0) {
|
||||
/* the request is already cancelled. Return. */
|
||||
return;
|
||||
}
|
||||
info->cancellable_id = signal_id;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error)
|
||||
{
|
||||
GTask *task = G_TASK(result);
|
||||
|
||||
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper));
|
||||
|
||||
return g_task_propagate_pointer(task, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,4 +420,13 @@ guint8 nm_wifi_utils_level_to_quality(int val);
|
|||
#define NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN "Unable to determine UID of the request"
|
||||
#define NM_UTILS_ERROR_MSG_INSUFF_PRIV "Insufficient privileges"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void nm_utils_spawn_helper(const char *const * args,
|
||||
GCancellable * cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data);
|
||||
|
||||
char *nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error);
|
||||
|
||||
#endif /* __NM_CORE_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -6306,3 +6306,20 @@ nm_crypto_md5_hash(const guint8 *salt,
|
|||
g_checksum_update(ctx, digest.ptr, NM_UTILS_CHECKSUM_LENGTH_MD5);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
char *
|
||||
nm_utils_get_process_exit_status_desc(int status)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
return g_strdup_printf("exited with status %d", WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status))
|
||||
return g_strdup_printf("killed by signal %d", WTERMSIG(status));
|
||||
else if (WIFSTOPPED(status))
|
||||
return g_strdup_printf("stopped by signal %d", WSTOPSIG(status));
|
||||
else if (WIFCONTINUED(status))
|
||||
return g_strdup("resumed by SIGCONT)");
|
||||
else
|
||||
return g_strdup_printf("exited with unknown status 0x%x", status);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,7 +277,29 @@ nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src)
|
|||
nm_assert(dst);
|
||||
nm_assert(src);
|
||||
|
||||
memcpy(dst, src, (addr_family != AF_INET6) ? sizeof(in_addr_t) : sizeof(struct in6_addr));
|
||||
memcpy(dst, src, NM_IS_IPv4(addr_family) ? sizeof(in_addr_t) : sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
static inline NMIPAddr
|
||||
nm_ip_addr_init(int addr_family, gconstpointer src)
|
||||
{
|
||||
NMIPAddr a;
|
||||
|
||||
nm_assert_addr_family(addr_family);
|
||||
nm_assert(src);
|
||||
|
||||
G_STATIC_ASSERT_EXPR(sizeof(NMIPAddr) == sizeof(struct in6_addr));
|
||||
|
||||
if (NM_IS_IPv4(addr_family)) {
|
||||
memcpy(&a, src, sizeof(in_addr_t));
|
||||
|
||||
/* ensure all bytes of the union are initialized. If only to make
|
||||
* valgrind happy. */
|
||||
memset(&a.array[sizeof(in_addr_t)], 0, sizeof(a) - sizeof(in_addr_t));
|
||||
} else
|
||||
memcpy(&a, src, sizeof(struct in6_addr));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
gboolean nm_ip_addr_set_from_untrusted(int addr_family,
|
||||
|
|
@ -2920,4 +2942,8 @@ void nm_crypto_md5_hash(const guint8 *salt,
|
|||
guint8 * buffer,
|
||||
gsize buflen);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
char *nm_utils_get_process_exit_status_desc(int status);
|
||||
|
||||
#endif /* __NM_SHARED_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ if enable_nmtui
|
|||
endif
|
||||
subdir('nmcli')
|
||||
subdir('nm-dispatcher')
|
||||
subdir('nm-daemon-helper')
|
||||
subdir('nm-online')
|
||||
if enable_nmtui
|
||||
subdir('nmtui')
|
||||
|
|
|
|||
15
src/nm-daemon-helper/meson.build
Normal file
15
src/nm-daemon-helper/meson.build
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
executable(
|
||||
'nm-daemon-helper',
|
||||
'nm-daemon-helper.c',
|
||||
include_directories : [
|
||||
src_inc,
|
||||
top_inc,
|
||||
],
|
||||
link_with: [
|
||||
libnm_std_aux,
|
||||
],
|
||||
link_args: ldflags_linker_script_binary,
|
||||
link_depends: linker_script_binary,
|
||||
install: true,
|
||||
install_dir: nm_libexecdir,
|
||||
)
|
||||
112
src/nm-daemon-helper/nm-daemon-helper.c
Normal file
112
src/nm-daemon-helper/nm-daemon-helper.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
/* Copyright (C) 2021 Red Hat, Inc. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <nss.h>
|
||||
|
||||
#include "libnm-std-aux/nm-std-aux.h"
|
||||
|
||||
enum {
|
||||
RETURN_SUCCESS = 0,
|
||||
RETURN_INVALID_CMD = 1,
|
||||
RETURN_INVALID_ARGS = 2,
|
||||
RETURN_ERROR = 3,
|
||||
};
|
||||
|
||||
static char *
|
||||
read_arg(void)
|
||||
{
|
||||
nm_auto_free char *arg = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
if (getdelim(&arg, &len, '\0', stdin) < 0)
|
||||
return NULL;
|
||||
|
||||
return nm_steal_pointer(&arg);
|
||||
}
|
||||
|
||||
static int
|
||||
more_args(void)
|
||||
{
|
||||
nm_auto_free char *arg = NULL;
|
||||
|
||||
arg = read_arg();
|
||||
|
||||
return !!arg;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_version(void)
|
||||
{
|
||||
if (more_args())
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
printf("1");
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
cmd_resolve_address(void)
|
||||
{
|
||||
nm_auto_free char *address = NULL;
|
||||
union {
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
} sockaddr;
|
||||
socklen_t sockaddr_size;
|
||||
char name[NI_MAXHOST];
|
||||
|
||||
address = read_arg();
|
||||
if (!address)
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
if (more_args())
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
__nss_configure_lookup("hosts", "dns");
|
||||
|
||||
if (inet_pton(AF_INET, address, &sockaddr.in.sin_addr) == 1) {
|
||||
sockaddr.in.sin_family = AF_INET;
|
||||
sockaddr_size = sizeof(struct sockaddr_in);
|
||||
} else if (inet_pton(AF_INET6, address, &sockaddr.in6.sin6_addr) == 1) {
|
||||
sockaddr.in6.sin6_family = AF_INET6;
|
||||
sockaddr_size = sizeof(struct sockaddr_in6);
|
||||
} else
|
||||
return RETURN_INVALID_ARGS;
|
||||
|
||||
if (getnameinfo((struct sockaddr *) &sockaddr,
|
||||
sockaddr_size,
|
||||
name,
|
||||
sizeof(name),
|
||||
NULL,
|
||||
0,
|
||||
NI_NAMEREQD)
|
||||
!= 0)
|
||||
return RETURN_ERROR;
|
||||
|
||||
printf("%s", name);
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
nm_auto_free char *cmd = NULL;
|
||||
|
||||
cmd = read_arg();
|
||||
if (!cmd)
|
||||
return RETURN_INVALID_CMD;
|
||||
|
||||
if (nm_streq(cmd, "version"))
|
||||
return cmd_version();
|
||||
if (nm_streq(cmd, "resolve-address"))
|
||||
return cmd_resolve_address();
|
||||
|
||||
return RETURN_INVALID_CMD;
|
||||
}
|
||||
|
|
@ -361,8 +361,8 @@ complete_script(ScriptInfo *script)
|
|||
static void
|
||||
script_watch_cb(GPid pid, int status, gpointer user_data)
|
||||
{
|
||||
ScriptInfo *script = user_data;
|
||||
guint err;
|
||||
ScriptInfo * script = user_data;
|
||||
gs_free char *status_desc = NULL;
|
||||
|
||||
g_assert(pid == script->pid);
|
||||
|
||||
|
|
@ -372,23 +372,11 @@ script_watch_cb(GPid pid, int status, gpointer user_data)
|
|||
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));
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
|
||||
script->result = DISPATCH_RESULT_SUCCESS;
|
||||
} else {
|
||||
script->error = g_strdup_printf("Script '%s' died from an unknown cause", script->script);
|
||||
status_desc = nm_utils_get_process_exit_status_desc(status);
|
||||
script->error = g_strdup_printf("Script '%s' %s.", script->script, status_desc);
|
||||
}
|
||||
|
||||
if (script->result == DISPATCH_RESULT_SUCCESS) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue