core: merge branch 'th/async-bgo781643'

https://bugzilla.gnome.org/show_bug.cgi?id=781643
This commit is contained in:
Thomas Haller 2017-05-12 17:41:12 +02:00
commit 36e7a1f8a0
20 changed files with 1999 additions and 1215 deletions

View file

@ -1391,6 +1391,9 @@ src_libNetworkManager_la_SOURCES = \
src/ppp/nm-ppp-manager.h \
src/ppp/nm-ppp-status.h \
\
src/nm-hostname-manager.c \
src/nm-hostname-manager.h \
\
src/settings/nm-agent-manager.c \
src/settings/nm-agent-manager.h \
src/settings/nm-inotify-helper.c \

View file

@ -49,6 +49,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
char *path;
GDBusProxy *proxy;
GCancellable *proxy_cancellable;
gboolean initialized;
char *address;
@ -73,6 +74,11 @@ G_DEFINE_TYPE (NMBluez4Adapter, nm_bluez4_adapter, G_TYPE_OBJECT)
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_BT
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bluez4-adapter", __VA_ARGS__)
/*****************************************************************************/
static void device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device);
/*****************************************************************************/
@ -119,8 +125,8 @@ nm_bluez4_adapter_get_devices (NMBluez4Adapter *self)
static void
emit_device_removed (NMBluez4Adapter *self, NMBluezDevice *device)
{
nm_log_dbg (LOGD_BT, "(%s): bluez device now unusable",
nm_bluez_device_get_path (device));
_LOGD ("(%s): bluez device now unusable",
nm_bluez_device_get_path (device));
g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
}
@ -130,9 +136,9 @@ device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data)
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data);
if (nm_bluez_device_get_usable (device)) {
nm_log_dbg (LOGD_BT, "(%s): bluez device now usable (device address is %s)",
nm_bluez_device_get_path (device),
nm_bluez_device_get_address (device));
_LOGD ("(%s): bluez device now usable (device address is %s)",
nm_bluez_device_get_path (device),
nm_bluez_device_get_address (device));
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
} else
emit_device_removed (self, device);
@ -143,9 +149,9 @@ device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data)
{
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data);
nm_log_dbg (LOGD_BT, "(%s): bluez device %s",
nm_bluez_device_get_path (device),
success ? "initialized" : "failed to initialize");
_LOGD ("(%s): bluez device %s",
nm_bluez_device_get_path (device),
success ? "initialized" : "failed to initialize");
if (!success)
device_do_remove (self, device);
}
@ -178,7 +184,7 @@ device_created (GDBusProxy *proxy, const char *path, gpointer user_data)
g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self);
g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device);
nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path);
_LOGD ("(%s): new bluez device found", path);
}
static void
@ -188,7 +194,7 @@ device_removed (GDBusProxy *proxy, const char *path, gpointer user_data)
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
NMBluezDevice *device;
nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path);
_LOGD ("(%s): bluez device removed", path);
device = g_hash_table_lookup (priv->devices, path);
if (device)
@ -198,19 +204,28 @@ device_removed (GDBusProxy *proxy, const char *path, gpointer user_data)
static void
get_properties_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
{
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data);
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
GError *err = NULL;
NMBluez4Adapter *self;
NMBluez4AdapterPrivate *priv;
gs_free_error GError *error = NULL;
GVariant *ret, *properties;
char **devices;
int i;
ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
G_VARIANT_TYPE ("(a{sv})"), &err);
G_VARIANT_TYPE ("(a{sv})"), &error);
if ( !ret
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_BLUEZ4_ADAPTER (user_data);
priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
g_clear_object (&priv->proxy_cancellable);
if (!ret) {
g_dbus_error_strip_remote_error (err);
nm_log_warn (LOGD_BT, "bluez error getting adapter properties: %s", err->message);
g_error_free (err);
g_dbus_error_strip_remote_error (error);
_LOGW ("bluez error getting adapter properties: %s", error->message);
goto done;
}
@ -233,15 +248,43 @@ done:
}
static void
query_properties (NMBluez4Adapter *self)
_proxy_new_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
NMBluez4Adapter *self;
NMBluez4AdapterPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
if (!proxy) {
_LOGW ("bluez error creating D-Bus proxy: %s", error->message);
g_clear_object (&priv->proxy_cancellable);
g_signal_emit (self, signals[INITIALIZED], 0, priv->initialized);
return;
}
priv->proxy = proxy;
_nm_dbus_signal_connect (priv->proxy, "DeviceCreated", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (device_created), self);
_nm_dbus_signal_connect (priv->proxy, "DeviceRemoved", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (device_removed), self);
g_dbus_proxy_call (priv->proxy, "GetProperties",
NULL,
G_DBUS_CALL_FLAGS_NONE, -1,
NULL,
get_properties_cb, self);
priv->proxy_cancellable,
get_properties_cb,
self);
}
/*****************************************************************************/
@ -316,19 +359,17 @@ nm_bluez4_adapter_new (const char *path, NMSettings *settings)
priv->settings = g_object_ref (settings);
priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
BLUEZ_SERVICE,
priv->path,
BLUEZ4_ADAPTER_INTERFACE,
NULL, NULL);
_nm_dbus_signal_connect (priv->proxy, "DeviceCreated", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (device_created), self);
_nm_dbus_signal_connect (priv->proxy, "DeviceRemoved", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (device_removed), self);
priv->proxy_cancellable = g_cancellable_new ();
query_properties (self);
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
BLUEZ_SERVICE,
priv->path,
BLUEZ4_ADAPTER_INTERFACE,
priv->proxy_cancellable,
_proxy_new_cb,
self);
return self;
}
@ -339,21 +380,28 @@ dispose (GObject *object)
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
NMBluezDevice *device;
nm_clear_g_cancellable (&priv->proxy_cancellable);
while ((device = g_hash_table_find (priv->devices, _find_all, NULL)))
device_do_remove (self, device);
if (priv->proxy) {
g_signal_handlers_disconnect_by_data (priv->proxy, self);
g_clear_object (&priv->proxy);
}
G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE ((NMBluez4Adapter *) object);
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (object);
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
g_hash_table_destroy (priv->devices);
g_free (priv->address);
g_free (priv->path);
g_object_unref (priv->proxy);
G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->finalize (object);

View file

@ -47,6 +47,7 @@ typedef struct {
NMSettings *settings;
GDBusProxy *proxy;
GCancellable *proxy_cancellable;
NMBluez4Adapter *adapter;
} NMBluez4ManagerPrivate;
@ -66,6 +67,11 @@ G_DEFINE_TYPE (NMBluez4Manager, nm_bluez4_manager, G_TYPE_OBJECT)
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_BT
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bluez4-manager", __VA_ARGS__)
/*****************************************************************************/
static void
emit_bdaddr_added (NMBluez4Manager *self, NMBluezDevice *device)
{
@ -176,42 +182,62 @@ default_adapter_changed (GDBusProxy *proxy, const char *path, NMBluez4Manager *s
static void
default_adapter_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
{
NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data);
NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
GVariant *ret;
GError *err = NULL;
NMBluez4Manager *self;
NMBluez4ManagerPrivate *priv;
gs_unref_variant GVariant *ret = NULL;
gs_free_error GError *error = NULL;
const char *default_adapter;
ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
G_VARIANT_TYPE ("(o)"), &err);
if (ret) {
const char *default_adapter;
G_VARIANT_TYPE ("(o)"), &error);
if ( !ret
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_variant_get (ret, "(&o)", &default_adapter);
default_adapter_changed (priv->proxy, default_adapter, self);
g_variant_unref (ret);
} else {
self = NM_BLUEZ4_MANAGER (user_data);
priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
g_clear_object (&priv->proxy_cancellable);
if (!ret) {
/* Ignore "No such adapter" errors; just means bluetooth isn't active */
if ( !_nm_dbus_error_has_name (err, "org.bluez.Error.NoSuchAdapter")
&& !_nm_dbus_error_has_name (err, "org.freedesktop.systemd1.LoadFailed")
&& !g_error_matches (err, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
g_dbus_error_strip_remote_error (err);
nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s",
err->message);
if ( !_nm_dbus_error_has_name (error, "org.bluez.Error.NoSuchAdapter")
&& !_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")
&& !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
g_dbus_error_strip_remote_error (error);
_LOGW ("bluez error getting default adapter: %s",
error->message);
}
g_error_free (err);
return;
}
g_variant_get (ret, "(&o)", &default_adapter);
default_adapter_changed (priv->proxy, default_adapter, self);
}
static void
query_default_adapter (NMBluez4Manager *self)
name_owner_changed (NMBluez4Manager *self)
{
NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
gs_free char *owner = NULL;
nm_clear_g_cancellable (&priv->proxy_cancellable);
owner = g_dbus_proxy_get_name_owner (priv->proxy);
if (!owner) {
/* Throwing away the adapter removes all devices too */
g_clear_object (&priv->adapter);
return;
}
priv->proxy_cancellable = g_cancellable_new ();
g_dbus_proxy_call (priv->proxy, "DefaultAdapter",
NULL,
G_DBUS_CALL_FLAGS_NONE, -1,
NULL,
default_adapter_cb, self);
priv->proxy_cancellable,
default_adapter_cb,
self);
}
static void
@ -219,18 +245,43 @@ name_owner_changed_cb (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data);
NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
char *owner;
name_owner_changed (user_data);
}
owner = g_dbus_proxy_get_name_owner (priv->proxy);
if (owner) {
query_default_adapter (self);
g_free (owner);
} else {
/* Throwing away the adapter removes all devices too */
g_clear_object (&priv->adapter);
static void
_proxy_new_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
NMBluez4Manager *self;
NMBluez4ManagerPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
if (!proxy) {
_LOGW ("bluez error creating D-Bus proxy: %s", error->message);
g_clear_object (&priv->proxy_cancellable);
return;
}
priv->proxy = proxy;
_nm_dbus_signal_connect (priv->proxy, "AdapterRemoved", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (adapter_removed), self);
_nm_dbus_signal_connect (priv->proxy, "DefaultAdapterChanged", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (default_adapter_changed), self);
g_signal_connect (priv->proxy, "notify::g-name-owner",
G_CALLBACK (name_owner_changed_cb), self);
name_owner_changed (self);
}
/*****************************************************************************/
@ -240,21 +291,17 @@ nm_bluez4_manager_init (NMBluez4Manager *self)
{
NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
BLUEZ_SERVICE,
BLUEZ_MANAGER_PATH,
BLUEZ4_MANAGER_INTERFACE,
NULL, NULL);
_nm_dbus_signal_connect (priv->proxy, "AdapterRemoved", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (adapter_removed), self);
_nm_dbus_signal_connect (priv->proxy, "DefaultAdapterChanged", G_VARIANT_TYPE ("(o)"),
G_CALLBACK (default_adapter_changed), self);
g_signal_connect (priv->proxy, "notify::g-name-owner",
G_CALLBACK (name_owner_changed_cb), self);
priv->proxy_cancellable = g_cancellable_new ();
query_default_adapter (self);
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
BLUEZ_SERVICE,
BLUEZ_MANAGER_PATH,
BLUEZ4_MANAGER_INTERFACE,
priv->proxy_cancellable,
_proxy_new_cb,
self);
}
NMBluez4Manager *
@ -275,7 +322,13 @@ dispose (GObject *object)
NMBluez4Manager *self = NM_BLUEZ4_MANAGER (object);
NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
g_clear_object (&priv->proxy);
nm_clear_g_cancellable (&priv->proxy_cancellable);
if (priv->proxy) {
g_signal_handlers_disconnect_by_data (priv->proxy, self);
g_clear_object (&priv->proxy);
}
g_clear_object (&priv->adapter);
G_OBJECT_CLASS (nm_bluez4_manager_parent_class)->dispose (object);

View file

@ -40,15 +40,14 @@
#include "nm-bt-error.h"
#include "platform/nm-platform.h"
#include "devices/wwan/nm-modem-manager.h"
#include "devices/wwan/nm-modem.h"
#include "introspection/org.freedesktop.NetworkManager.Device.Bluetooth.h"
#include "devices/nm-device-logging.h"
_LOG_DECLARE_SELF(NMDeviceBt);
#define MM_DBUS_SERVICE "org.freedesktop.ModemManager1"
#define MM_DBUS_PATH "/org/freedesktop/ModemManager1"
#define MM_DBUS_INTERFACE "org.freedesktop.ModemManager1"
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
@ -65,7 +64,8 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
GDBusProxy *mm_proxy;
NMModemManager *modem_manager;
gboolean mm_running;
NMBluezDevice *bt_device;
@ -967,9 +967,12 @@ is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
}
static void
set_mm_running (NMDeviceBt *self, gboolean running)
set_mm_running (NMDeviceBt *self)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
gboolean running;
running = (nm_modem_manager_name_owner_get (priv->modem_manager) != NULL);
if (priv->mm_running != running) {
_LOGD (LOGD_BT, "ModemManager now %s",
@ -983,18 +986,11 @@ set_mm_running (NMDeviceBt *self, gboolean running)
}
static void
mm_name_owner_changed (GObject *object,
GParamSpec *pspec,
NMDeviceBt *self)
mm_name_owner_changed_cb (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
char *owner;
owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object));
if (owner) {
set_mm_running (self, TRUE);
g_free (owner);
} else
set_mm_running (self, FALSE);
set_mm_running (user_data);
}
/*****************************************************************************/
@ -1039,7 +1035,8 @@ set_property (GObject *object, guint prop_id,
case PROP_BT_DEVICE:
/* construct-only */
priv->bt_device = g_value_dup_object (value);
g_signal_connect (priv->bt_device, "removed", G_CALLBACK (bluez_device_removed), object);
if (!priv->bt_device)
g_return_if_reached ();
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -1052,46 +1049,41 @@ set_property (GObject *object, guint prop_id,
static void
nm_device_bt_init (NMDeviceBt *self)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
GError *error = NULL;
priv->mm_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
MM_DBUS_SERVICE,
MM_DBUS_PATH,
MM_DBUS_INTERFACE,
NULL, &error);
if (priv->mm_proxy) {
g_signal_connect (priv->mm_proxy, "notify::g-name-owner",
G_CALLBACK (mm_name_owner_changed),
self);
mm_name_owner_changed (G_OBJECT (priv->mm_proxy), NULL, self);
} else {
_LOGW (LOGD_MB, "Could not create proxy for '%s': %s",
MM_DBUS_SERVICE, error->message);
g_clear_error (&error);
}
}
static void
constructed (GObject *object)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object);
NMDeviceBt *self = NM_DEVICE_BT (object);
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
const char *my_hwaddr;
G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object);
my_hwaddr = nm_device_get_hw_address (NM_DEVICE (object));
g_assert (my_hwaddr);
priv->bdaddr = g_strdup (my_hwaddr);
priv->modem_manager = g_object_ref (nm_modem_manager_get ());
/* Watch for BT device property changes */
g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED,
G_CALLBACK (bluez_connected_changed),
object);
nm_modem_manager_name_owner_ref (priv->modem_manager);
g_signal_connect (priv->modem_manager,
"notify::"NM_MODEM_MANAGER_NAME_OWNER,
G_CALLBACK (mm_name_owner_changed_cb),
self);
if (priv->bt_device) {
/* Watch for BT device property changes */
g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED,
G_CALLBACK (bluez_connected_changed),
object);
g_signal_connect (priv->bt_device, "removed", G_CALLBACK (bluez_device_removed), object);
}
my_hwaddr = nm_device_get_hw_address (NM_DEVICE (object));
if (my_hwaddr)
priv->bdaddr = g_strdup (my_hwaddr);
else
g_warn_if_reached ();
set_mm_running (self);
}
NMDevice *
@ -1129,9 +1121,10 @@ dispose (GObject *object)
g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
if (priv->mm_proxy) {
g_signal_handlers_disconnect_by_func (priv->mm_proxy, G_CALLBACK (mm_name_owner_changed), object);
g_clear_object (&priv->mm_proxy);
if (priv->modem_manager) {
g_signal_handlers_disconnect_by_func (priv->modem_manager, G_CALLBACK (mm_name_owner_changed_cb), object);
nm_modem_manager_name_owner_unref (priv->modem_manager);
g_clear_object (&priv->modem_manager);
}
modem_cleanup (NM_DEVICE_BT (object));

View file

@ -24,8 +24,6 @@
#include "devices/nm-device.h"
#include "nm-bluez-device.h"
#include "devices/wwan/nm-modem.h"
#define NM_TYPE_DEVICE_BT (nm_device_bt_get_type ())
#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BT, NMDeviceBt))
#define NM_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass))
@ -52,8 +50,10 @@ NMDevice *nm_device_bt_new (NMBluezDevice *bt_device,
guint32 nm_device_bt_get_capabilities (NMDeviceBt *device);
struct _NMModem;
gboolean nm_device_bt_modem_added (NMDeviceBt *device,
NMModem *modem,
struct _NMModem *modem,
const char *driver);
#endif /* __NETWORKMANAGER_DEVICE_BT_H__ */

View file

@ -20,7 +20,11 @@ global:
nm_modem_get_type;
nm_modem_get_uid;
nm_modem_ip4_pre_commit;
nm_modem_manager_get;
nm_modem_manager_get_type;
nm_modem_manager_name_owner_get;
nm_modem_manager_name_owner_ref;
nm_modem_manager_name_owner_unref;
nm_modem_owns_port;
nm_modem_set_mm_enabled;
nm_modem_stage3_ip4_config_start;

File diff suppressed because it is too large Load diff

View file

@ -34,9 +34,22 @@
#define NM_MODEM_MANAGER_MODEM_ADDED "modem-added"
#define NM_MODEM_MANAGER_NAME_OWNER "name-owner"
#define NM_MODEM_MANAGER_MM_DBUS_SERVICE "org.freedesktop.ModemManager1"
#define NM_MODEM_MANAGER_MM_DBUS_PATH "/org/freedesktop/ModemManager1"
#define NM_MODEM_MANAGER_MM_DBUS_INTERFACE "org.freedesktop.ModemManager1"
typedef struct _NMModemManager NMModemManager;
typedef struct _NMModemManagerClass NMModemManagerClass;
GType nm_modem_manager_get_type (void);
NMModemManager *nm_modem_manager_get (void);
void nm_modem_manager_name_owner_ref (NMModemManager *self);
void nm_modem_manager_name_owner_unref (NMModemManager *self);
const char *nm_modem_manager_name_owner_get (NMModemManager *self);
#endif /* __NETWORKMANAGER_MODEM_MANAGER_H__ */

View file

@ -46,6 +46,11 @@ typedef struct {
GDBusProxy *context_proxy;
GDBusProxy *sim_proxy;
GCancellable *modem_proxy_cancellable;
GCancellable *connman_proxy_cancellable;
GCancellable *context_proxy_cancellable;
GCancellable *sim_proxy_cancellable;
GError *property_error;
char *context_path;
@ -165,28 +170,16 @@ typedef struct {
static void
disconnect_context_complete (DisconnectContext *ctx)
{
g_simple_async_result_complete_in_idle (ctx->result);
if (ctx->cancellable)
g_object_unref (ctx->cancellable);
g_object_unref (ctx->result);
if (ctx->result) {
g_simple_async_result_complete_in_idle (ctx->result);
g_object_unref (ctx->result);
}
g_object_unref (ctx->self);
g_slice_free (DisconnectContext, ctx);
}
static gboolean
disconnect_context_complete_if_cancelled (DisconnectContext *ctx)
{
GError *error = NULL;
if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) {
g_simple_async_result_take_error (ctx->result, error);
disconnect_context_complete (ctx);
return TRUE;
}
return FALSE;
}
static gboolean
disconnect_finish (NMModem *self,
GAsyncResult *result,
@ -196,25 +189,25 @@ disconnect_finish (NMModem *self,
}
static void
disconnect_done (GDBusProxy *proxy,
GAsyncResult *result,
gpointer user_data)
disconnect_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
DisconnectContext *ctx = (DisconnectContext*) user_data;
NMModemOfono *self = ctx->self;
GError *error = NULL;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *v = NULL;
g_dbus_proxy_call_finish (proxy, result, &error);
v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
_LOGD ("disconnect cancelled");
if (ctx->result)
g_simple_async_result_take_error (ctx->result, g_steal_pointer (&error));
disconnect_context_complete (ctx);
return;
}
if (error) {
if (ctx->warn)
_LOGW ("failed to disconnect modem: %s", error->message);
g_clear_error (&error);
}
if (error && ctx->warn)
_LOGW ("failed to disconnect modem: %s", error->message);
_LOGD ("modem disconnected");
@ -233,18 +226,15 @@ disconnect (NMModem *modem,
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
DisconnectContext *ctx;
NMModemState state = nm_modem_get_state (NM_MODEM (self));
GError *error = NULL;
_LOGD ("warn: %s modem_state: %s",
warn ? "TRUE" : "FALSE",
nm_modem_state_to_string (state));
if (state != NM_MODEM_STATE_CONNECTED)
return;
ctx = g_slice_new (DisconnectContext);
ctx = g_slice_new0 (DisconnectContext);
ctx->self = g_object_ref (self);
ctx->warn = warn;
if (callback) {
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
@ -252,9 +242,28 @@ disconnect (NMModem *modem,
disconnect);
}
ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
if (disconnect_context_complete_if_cancelled (ctx))
if (state != NM_MODEM_STATE_CONNECTED) {
if (ctx->result) {
g_set_error_literal (&error,
NM_UTILS_ERROR,
NM_UTILS_ERROR_UNKNOWN,
("modem is currently not connected"));
g_simple_async_result_take_error (ctx->result, error);
}
disconnect_context_complete (ctx);
return;
}
if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
if (ctx->result)
g_simple_async_result_take_error (ctx->result, error);
else
g_clear_error (&error);
disconnect_context_complete (ctx);
return;
}
ctx->cancellable = nm_g_object_ref (cancellable);
nm_modem_set_state (NM_MODEM (self),
NM_MODEM_STATE_DISCONNECTING,
@ -267,8 +276,8 @@ disconnect (NMModem *modem,
g_variant_new ("b", warn)),
G_DBUS_CALL_FLAGS_NONE,
20000,
NULL,
(GAsyncReadyCallback) disconnect_done,
ctx->cancellable,
disconnect_done,
ctx);
}
@ -375,22 +384,35 @@ sim_property_changed (GDBusProxy *proxy,
}
static void
sim_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
sim_get_properties_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data);
GError *error = NULL;
GVariant *v_properties, *v_dict, *v;
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *v_properties = NULL;
gs_unref_variant GVariant *v_dict = NULL;
GVariant *v;
GVariantIter i;
const char *property;
v_properties = _nm_dbus_proxy_call_finish (proxy,
v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source),
result,
G_VARIANT_TYPE ("(a{sv})"),
&error);
if ( !v_properties
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_MODEM_OFONO (user_data);
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
g_clear_object (&priv->sim_proxy_cancellable);
if (!v_properties) {
g_dbus_error_strip_remote_error (error);
_LOGW ("error getting sim properties: %s", error->message);
g_error_free (error);
return;
}
@ -418,9 +440,49 @@ sim_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_
handle_sim_property (NULL, property, v, self);
g_variant_unref (v);
}
}
g_variant_unref (v_dict);
g_variant_unref (v_properties);
static void
_sim_proxy_new_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
if (!proxy) {
_LOGW ("failed to create SimManager proxy: %s", error->message);
g_clear_object (&priv->sim_proxy_cancellable);
return;
}
priv->sim_proxy = proxy;
/* Watch for custom ofono PropertyChanged signals */
_nm_dbus_signal_connect (priv->sim_proxy,
"PropertyChanged",
G_VARIANT_TYPE ("(sv)"),
G_CALLBACK (sim_property_changed),
self);
g_dbus_proxy_call (priv->sim_proxy,
"GetProperties",
NULL,
G_DBUS_CALL_FLAGS_NONE,
20000,
priv->sim_proxy_cancellable,
sim_get_properties_done,
self);
}
static void
@ -430,47 +492,30 @@ handle_sim_iface (NMModemOfono *self, gboolean found)
_LOGD ("SimManager interface %sfound", found ? "" : "not ");
if (!found && priv->sim_proxy) {
if (!found && (priv->sim_proxy || priv->sim_proxy_cancellable)) {
_LOGI ("SimManager interface disappeared");
g_signal_handlers_disconnect_by_data (priv->sim_proxy, NM_MODEM_OFONO (self));
g_clear_object (&priv->sim_proxy);
nm_clear_g_cancellable (&priv->sim_proxy_cancellable);
if (priv->sim_proxy) {
g_signal_handlers_disconnect_by_data (priv->sim_proxy, self);
g_clear_object (&priv->sim_proxy);
}
g_clear_pointer (&priv->imsi, g_free);
update_modem_state (self);
} else if (found && !priv->sim_proxy) {
GError *error = NULL;
} else if (found && (!priv->sim_proxy && !priv->sim_proxy_cancellable)) {
_LOGI ("found new SimManager interface");
priv->sim_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL, /* GDBusInterfaceInfo */
OFONO_DBUS_SERVICE,
nm_modem_get_path (NM_MODEM (self)),
OFONO_DBUS_INTERFACE_SIM_MANAGER,
NULL, /* GCancellable */
&error);
if (priv->sim_proxy == NULL) {
_LOGW ("failed to create SimManager proxy: %s", error->message);
g_error_free (error);
return;
}
priv->sim_proxy_cancellable = g_cancellable_new ();
/* Watch for custom ofono PropertyChanged signals */
_nm_dbus_signal_connect (priv->sim_proxy,
"PropertyChanged",
G_VARIANT_TYPE ("(sv)"),
G_CALLBACK (sim_property_changed),
self);
g_dbus_proxy_call (priv->sim_proxy,
"GetProperties",
NULL,
G_DBUS_CALL_FLAGS_NONE,
20000,
NULL,
(GAsyncReadyCallback) sim_get_properties_done,
g_object_ref (self));
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL, /* GDBusInterfaceInfo */
OFONO_DBUS_SERVICE,
nm_modem_get_path (NM_MODEM (self)),
OFONO_DBUS_INTERFACE_SIM_MANAGER,
priv->sim_proxy_cancellable, /* GCancellable */
_sim_proxy_new_cb,
self);
}
}
@ -514,22 +559,35 @@ connman_property_changed (GDBusProxy *proxy,
}
static void
connman_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
connman_get_properties_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data);
GError *error = NULL;
GVariant *v_properties, *v_dict, *v;
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *v_properties = NULL;
gs_unref_variant GVariant *v_dict = NULL;
GVariant *v;
GVariantIter i;
const char *property;
v_properties = _nm_dbus_proxy_call_finish (proxy,
result,
G_VARIANT_TYPE ("(a{sv})"),
&error);
v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source),
result,
G_VARIANT_TYPE ("(a{sv})"),
&error);
if ( !v_properties
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_MODEM_OFONO (user_data);
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
g_clear_object (&priv->connman_proxy_cancellable);
if (!v_properties) {
g_dbus_error_strip_remote_error (error);
_LOGW ("error getting connman properties: %s", error->message);
g_error_free (error);
return;
}
@ -549,9 +607,48 @@ connman_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer u
handle_connman_property (NULL, property, v, self);
g_variant_unref (v);
}
}
g_variant_unref (v_dict);
g_variant_unref (v_properties);
static void
_connman_proxy_new_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = user_data;
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
if (!proxy) {
_LOGW ("failed to create ConnectionManager proxy: %s", error->message);
g_clear_object (&priv->connman_proxy_cancellable);
return;
}
priv->connman_proxy = proxy;
_nm_dbus_signal_connect (priv->connman_proxy,
"PropertyChanged",
G_VARIANT_TYPE ("(sv)"),
G_CALLBACK (connman_property_changed),
self);
g_dbus_proxy_call (priv->connman_proxy,
"GetProperties",
NULL,
G_DBUS_CALL_FLAGS_NONE,
20000,
priv->connman_proxy_cancellable,
connman_get_properties_done,
self);
}
static void
@ -561,11 +658,13 @@ handle_connman_iface (NMModemOfono *self, gboolean found)
_LOGD ("ConnectionManager interface %sfound", found ? "" : "not ");
if (!found && priv->connman_proxy) {
if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) {
_LOGI ("ConnectionManager interface disappeared");
g_signal_handlers_disconnect_by_data (priv->connman_proxy, NM_MODEM_OFONO (self));
g_clear_object (&priv->connman_proxy);
nm_clear_g_cancellable (&priv->connman_proxy_cancellable);
if (priv->connman_proxy) {
g_signal_handlers_disconnect_by_data (priv->connman_proxy, self);
g_clear_object (&priv->connman_proxy);
}
/* The connection manager proxy disappeared, we should
* consider the modem disabled.
@ -573,41 +672,21 @@ handle_connman_iface (NMModemOfono *self, gboolean found)
priv->gprs_attached = FALSE;
update_modem_state (self);
} else if (found && !priv->connman_proxy) {
GError *error = NULL;
} else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) {
_LOGI ("found new ConnectionManager interface");
priv->connman_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL, /* GDBusInterfaceInfo */
OFONO_DBUS_SERVICE,
nm_modem_get_path (NM_MODEM (self)),
OFONO_DBUS_INTERFACE_CONNECTION_MANAGER,
NULL, /* GCancellable */
&error);
if (priv->connman_proxy == NULL) {
_LOGW ("failed to create ConnectionManager proxy: %s", error->message);
g_error_free (error);
return;
}
priv->connman_proxy_cancellable = g_cancellable_new ();
/* Watch for custom ofono PropertyChanged signals */
_nm_dbus_signal_connect (priv->connman_proxy,
"PropertyChanged",
G_VARIANT_TYPE ("(sv)"),
G_CALLBACK (connman_property_changed),
self);
g_dbus_proxy_call (priv->connman_proxy,
"GetProperties",
NULL,
G_DBUS_CALL_FLAGS_NONE,
20000,
NULL,
(GAsyncReadyCallback) connman_get_properties_done,
g_object_ref (self));
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL, /* GDBusInterfaceInfo */
OFONO_DBUS_SERVICE,
nm_modem_get_path (NM_MODEM (self)),
OFONO_DBUS_INTERFACE_CONNECTION_MANAGER,
priv->connman_proxy_cancellable,
_connman_proxy_new_cb,
NULL);
}
}
@ -667,22 +746,35 @@ modem_property_changed (GDBusProxy *proxy,
}
static void
modem_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
modem_get_properties_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data);
GError *error = NULL;
GVariant *v_properties, *v_dict, *v;
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *v_properties = NULL;
gs_unref_variant GVariant *v_dict = NULL;
GVariant *v;
GVariantIter i;
const char *property;
v_properties = _nm_dbus_proxy_call_finish (proxy,
v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source),
result,
G_VARIANT_TYPE ("(a{sv})"),
&error);
if ( !v_properties
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_MODEM_OFONO (user_data);
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
g_clear_object (&priv->modem_proxy_cancellable);
if (!v_properties) {
g_dbus_error_strip_remote_error (error);
_LOGW ("error getting modem properties: %s", error->message);
g_error_free (error);
return;
}
@ -706,21 +798,29 @@ modem_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer use
handle_modem_property (NULL, property, v, self);
g_variant_unref (v);
}
g_variant_unref (v_dict);
g_variant_unref (v_properties);
}
static void
stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
stage1_prepare_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data);
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
GError *error = NULL;
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *v = NULL;
v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_MODEM_OFONO (user_data);
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
g_clear_object (&priv->context_proxy_cancellable);
g_clear_pointer (&priv->connect_properties, g_hash_table_destroy);
g_dbus_proxy_call_finish (proxy, result, &error);
if (error) {
_LOGW ("connection failed: %s", error->message);
@ -732,8 +832,6 @@ stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data
* leading to the connection being disabled, and a 5m
* timeout...
*/
g_clear_error (&error);
}
}
@ -946,21 +1044,33 @@ static_stage3_ip4_config_start (NMModem *modem,
}
static void
context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
context_proxy_new_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data);
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
GError *error = NULL;
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
priv->context_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if (error) {
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
|| g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_MODEM_OFONO (user_data);
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
if (!proxy) {
_LOGE ("failed to create ofono ConnectionContext DBus proxy: %s", error->message);
g_clear_object (&priv->context_proxy_cancellable);
nm_modem_emit_prepare_result (NM_MODEM (self), FALSE,
NM_DEVICE_STATE_REASON_MODEM_BUSY);
return;
}
priv->context_proxy = proxy;
if (!priv->gprs_attached) {
g_clear_object (&priv->context_proxy_cancellable);
nm_modem_emit_prepare_result (NM_MODEM (self), FALSE,
NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER);
return;
@ -972,7 +1082,6 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
*/
g_clear_object (&priv->ip4_config);
/* Watch for custom ofono PropertyChanged signals */
_nm_dbus_signal_connect (priv->context_proxy,
"PropertyChanged",
G_VARIANT_TYPE ("(sv)"),
@ -986,9 +1095,9 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
g_variant_new ("b", TRUE)),
G_DBUS_CALL_FLAGS_NONE,
20000,
NULL,
(GAsyncReadyCallback) stage1_prepare_done,
g_object_ref (self));
priv->context_proxy_cancellable,
stage1_prepare_done,
self);
}
static void
@ -998,16 +1107,20 @@ do_context_activate (NMModemOfono *self)
g_return_if_fail (NM_IS_MODEM_OFONO (self));
nm_clear_g_cancellable (&priv->context_proxy_cancellable);
g_clear_object (&priv->context_proxy);
priv->context_proxy_cancellable = g_cancellable_new ();
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
OFONO_DBUS_SERVICE,
priv->context_path,
OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT,
NULL,
(GAsyncReadyCallback) context_proxy_new_cb,
g_object_ref (self));
priv->context_proxy_cancellable,
context_proxy_new_cb,
self);
}
static GHashTable *
@ -1081,19 +1194,29 @@ act_stage1_prepare (NMModem *modem,
}
static void
modem_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
modem_proxy_new_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data);
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
GError *error = NULL;
NMModemOfono *self;
NMModemOfonoPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *proxy;
priv->modem_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if (error) {
proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
if ( !proxy
&& g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = NM_MODEM_OFONO (user_data);
priv = NM_MODEM_OFONO_GET_PRIVATE (self);
if (!proxy) {
_LOGE ("failed to create ofono modem DBus proxy: %s", error->message);
g_clear_object (&priv->modem_proxy_cancellable);
return;
}
/* Watch for custom ofono PropertyChanged signals */
priv->modem_proxy = proxy;
_nm_dbus_signal_connect (priv->modem_proxy,
"PropertyChanged",
G_VARIANT_TYPE ("(sv)"),
@ -1105,9 +1228,9 @@ modem_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
NULL,
G_DBUS_CALL_FLAGS_NONE,
20000,
NULL,
(GAsyncReadyCallback) modem_get_properties_done,
g_object_ref (self));
priv->modem_proxy_cancellable,
modem_get_properties_done,
self);
}
/*****************************************************************************/
@ -1121,6 +1244,9 @@ static void
constructed (GObject *object)
{
NMModemOfono *self = NM_MODEM_OFONO (object);
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
priv->modem_proxy_cancellable = g_cancellable_new ();
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
@ -1128,9 +1254,11 @@ constructed (GObject *object)
OFONO_DBUS_SERVICE,
nm_modem_get_path (NM_MODEM (self)),
OFONO_DBUS_INTERFACE_MODEM,
NULL,
(GAsyncReadyCallback) modem_proxy_new_cb,
g_object_ref (self));
priv->modem_proxy_cancellable,
modem_proxy_new_cb,
self);
G_OBJECT_CLASS (nm_modem_ofono_parent_class)->constructed (object);
}
NMModem *
@ -1163,6 +1291,11 @@ dispose (GObject *object)
NMModemOfono *self = NM_MODEM_OFONO (object);
NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self);
nm_clear_g_cancellable (&priv->modem_proxy_cancellable);
nm_clear_g_cancellable (&priv->connman_proxy_cancellable);
nm_clear_g_cancellable (&priv->context_proxy_cancellable);
nm_clear_g_cancellable (&priv->sim_proxy_cancellable);
if (priv->connect_properties) {
g_hash_table_destroy (priv->connect_properties);
priv->connect_properties = NULL;
@ -1171,15 +1304,22 @@ dispose (GObject *object)
g_clear_object (&priv->ip4_config);
if (priv->modem_proxy) {
g_signal_handlers_disconnect_by_data (priv->modem_proxy, NM_MODEM_OFONO (self));
g_signal_handlers_disconnect_by_data (priv->modem_proxy, self);
g_clear_object (&priv->modem_proxy);
}
g_clear_object (&priv->connman_proxy);
g_clear_object (&priv->context_proxy);
if (priv->connman_proxy) {
g_signal_handlers_disconnect_by_data (priv->connman_proxy, self);
g_clear_object (&priv->connman_proxy);
}
if (priv->context_proxy) {
g_signal_handlers_disconnect_by_data (priv->context_proxy, self);
g_clear_object (&priv->context_proxy);
}
if (priv->sim_proxy) {
g_signal_handlers_disconnect_by_data (priv->sim_proxy, NM_MODEM_OFONO (self));
g_signal_handlers_disconnect_by_data (priv->sim_proxy, self);
g_clear_object (&priv->sim_proxy);
}

View file

@ -1451,6 +1451,7 @@ set_property (GObject *object, guint prop_id,
case PROP_PATH:
/* construct-only */
priv->path = g_value_dup_string (value);
g_return_if_fail (priv->path);
break;
case PROP_DRIVER:
/* construct-only */
@ -1512,37 +1513,16 @@ nm_modem_init (NMModem *self)
self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
GObject *object;
NMModemPrivate *priv;
object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
G_OBJECT_CLASS (nm_modem_parent_class)->constructed (object);
priv = NM_MODEM_GET_PRIVATE ((NMModem *) object);
priv = NM_MODEM_GET_PRIVATE (NM_MODEM (object));
if (!priv->data_port && !priv->control_port) {
nm_log_err (LOGD_PLATFORM, "neither modem command nor data interface provided");
goto err;
}
if (!priv->path) {
nm_log_err (LOGD_PLATFORM, "D-Bus path not provided");
goto err;
}
return object;
err:
g_object_unref (object);
return NULL;
g_return_if_fail (priv->data_port || priv->control_port);
}
/*****************************************************************************/
@ -1552,10 +1532,7 @@ dispose (GObject *object)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object);
if (priv->act_request) {
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
g_clear_object (&priv->act_request);
G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object);
}
@ -1584,7 +1561,7 @@ nm_modem_class_init (NMModemClass *klass)
g_type_class_add_private (object_class, sizeof (NMModemPrivate));
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->dispose = dispose;

View file

@ -105,10 +105,12 @@ typedef enum { /*< underscore_name=nm_modem_state >*/
struct _NMModemPrivate;
typedef struct {
struct _NMModem {
GObject parent;
struct _NMModemPrivate *_priv;
} NMModem;
};
typedef struct _NMModem NMModem;
typedef struct {
GObjectClass parent;

View file

@ -127,8 +127,8 @@ start (NMDeviceFactory *factory)
NMWwanFactory *self = NM_WWAN_FACTORY (factory);
NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE (self);
priv->mm = g_object_new (NM_TYPE_MODEM_MANAGER, NULL);
g_assert (priv->mm);
priv->mm = g_object_ref (nm_modem_manager_get ());
g_signal_connect (priv->mm,
NM_MODEM_MANAGER_MODEM_ADDED,
G_CALLBACK (modem_added_cb),

View file

@ -1435,6 +1435,7 @@ nm_dns_manager_set_initial_hostname (NMDnsManager *self,
{
NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self);
g_free (priv->hostname);
priv->hostname = g_strdup (hostname);
}

661
src/nm-hostname-manager.c Normal file
View file

@ -0,0 +1,661 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2017 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-hostname-manager.h"
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
#include "nm-common-macros.h"
#include "nm-dbus-interface.h"
#include "nm-connection.h"
#include "nm-utils.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
/*****************************************************************************/
#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1"
#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1"
#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1"
#define HOSTNAME_FILE_DEFAULT "/etc/hostname"
#define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME"
#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname"
#if (defined(HOSTNAME_PERSIST_SUSE) + defined(HOSTNAME_PERSIST_SLACKWARE) + defined(HOSTNAME_PERSIST_GENTOO)) > 1
#error "Can only define one of HOSTNAME_PERSIST_*"
#endif
#if defined(HOSTNAME_PERSIST_SUSE)
#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
#elif defined(HOSTNAME_PERSIST_GENTOO)
#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO
#else
#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT
#endif
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE (NMHostnameManager,
PROP_HOSTNAME,
);
typedef struct {
char *current_hostname;
GFileMonitor *monitor;
GFileMonitor *dhcp_monitor;
gulong monitor_id;
gulong dhcp_monitor_id;
GDBusProxy *hostnamed_proxy;
} NMHostnameManagerPrivate;
struct _NMHostnameManager {
GObject parent;
NMHostnameManagerPrivate _priv;
};
struct _NMHostnameManagerClass {
GObjectClass parent;
};
G_DEFINE_TYPE (NMHostnameManager, nm_hostname_manager, G_TYPE_OBJECT);
#define NM_HOSTNAME_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMHostnameManager, NM_IS_HOSTNAME_MANAGER)
NM_DEFINE_SINGLETON_GETTER (NMHostnameManager, nm_hostname_manager_get, NM_TYPE_HOSTNAME_MANAGER);
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_CORE
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "hostname", __VA_ARGS__)
/*****************************************************************************/
#if defined(HOSTNAME_PERSIST_GENTOO)
static gchar *
read_hostname_gentoo (const char *path)
{
gs_free char *contents = NULL;
gs_strfreev char **all_lines = NULL;
const char *tmp;
guint i;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
for (i = 0; all_lines[i]; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
if (g_str_has_prefix (all_lines[i], "hostname=")) {
tmp = &all_lines[i][NM_STRLEN ("hostname=")];
return g_shell_unquote (tmp, NULL);
}
}
return NULL;
}
#endif
#if defined(HOSTNAME_PERSIST_SLACKWARE)
static gchar *
read_hostname_slackware (const char *path)
{
gs_free char *contents = NULL;
gs_strfreev char **all_lines = NULL;
char *tmp;
guint i, j = 0;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
for (i = 0; all_lines[i]; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
tmp = &all_lines[i][0];
/* We only want up to the first '.' -- the rest of the */
/* fqdn is defined in /etc/hosts */
while (tmp[j] != '\0') {
if (tmp[j] == '.') {
tmp[j] = '\0';
break;
}
j++;
}
return g_shell_unquote (tmp, NULL);
}
return NULL;
}
#endif
#if defined(HOSTNAME_PERSIST_SUSE)
static gboolean
hostname_is_dynamic (void)
{
GIOChannel *channel;
char *str = NULL;
gboolean dynamic = FALSE;
channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
if (!channel)
return dynamic;
while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
if (str) {
g_strstrip (str);
if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME="))
dynamic = strcmp (&str[NM_STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
g_free (str);
}
}
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return dynamic;
}
#endif
/* Returns an allocated string which the caller owns and must eventually free */
char *
nm_hostname_manager_read_hostname (NMHostnameManager *self)
{
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
char *hostname = NULL;
if (priv->hostnamed_proxy) {
hostname = g_strdup (priv->current_hostname);
goto out;
}
#if defined(HOSTNAME_PERSIST_SUSE)
if (priv->dhcp_monitor_id && hostname_is_dynamic ())
return NULL;
#endif
#if defined(HOSTNAME_PERSIST_GENTOO)
hostname = read_hostname_gentoo (HOSTNAME_FILE);
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
hostname = read_hostname_slackware (HOSTNAME_FILE);
#else
if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL))
g_strchomp (hostname);
#endif
out:
if (hostname && !hostname[0]) {
g_free (hostname);
return NULL;
}
return hostname;
}
/*****************************************************************************/
const char *
nm_hostname_manager_get_hostname (NMHostnameManager *self)
{
g_return_val_if_fail (NM_IS_HOSTNAME_MANAGER (self), NULL);
return NM_HOSTNAME_MANAGER_GET_PRIVATE (self)->current_hostname;
}
static void
_set_hostname_take (NMHostnameManager *self, char *hostname)
{
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
_LOGI ("hostname changed from %s%s%s to %s%s%s",
NM_PRINT_FMT_QUOTED (priv->current_hostname, "\"", priv->current_hostname, "\"", "(none)"),
NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
g_free (priv->current_hostname);
priv->current_hostname = hostname;
_notify (self, PROP_HOSTNAME);
}
static void
_set_hostname (NMHostnameManager *self, const char *hostname)
{
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
hostname = nm_str_not_empty (hostname);
if (!nm_streq0 (hostname, priv->current_hostname))
_set_hostname_take (self, g_strdup (hostname));
}
static void
_set_hostname_read (NMHostnameManager *self)
{
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
char *hostname;
if (priv->hostnamed_proxy) {
/* read-hostname returns the current hostname with hostnamed. */
return;
}
hostname = nm_hostname_manager_read_hostname (self);
if (nm_streq0 (hostname, priv->current_hostname)) {
g_free (hostname);
return;
}
_set_hostname_take (self, hostname);
}
/*****************************************************************************/
typedef struct {
char *hostname;
NMHostnameManagerSetHostnameCb cb;
gpointer user_data;
} SetHostnameInfo;
static void
set_transient_hostname_done (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GDBusProxy *proxy = G_DBUS_PROXY (object);
gs_free SetHostnameInfo *info = user_data;
gs_unref_variant GVariant *result = NULL;
gs_free_error GError *error = NULL;
result = g_dbus_proxy_call_finish (proxy, res, &error);
if (error) {
_LOGW ("couldn't set the system hostname to '%s' using hostnamed: %s",
info->hostname, error->message);
}
info->cb (info->hostname, !error, info->user_data);
g_free (info->hostname);
}
void
nm_hostname_manager_set_transient_hostname (NMHostnameManager *self,
const char *hostname,
NMHostnameManagerSetHostnameCb cb,
gpointer user_data)
{
NMHostnameManagerPrivate *priv;
SetHostnameInfo *info;
g_return_if_fail (NM_IS_HOSTNAME_MANAGER (self));
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
if (!priv->hostnamed_proxy) {
cb (hostname, FALSE, user_data);
return;
}
info = g_new0 (SetHostnameInfo, 1);
info->hostname = g_strdup (hostname);
info->cb = cb;
info->user_data = user_data;
g_dbus_proxy_call (priv->hostnamed_proxy,
"SetHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
set_transient_hostname_done,
info);
}
gboolean
nm_hostname_manager_get_transient_hostname (NMHostnameManager *self, char **hostname)
{
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
GVariant *v_hostname;
if (!priv->hostnamed_proxy)
return FALSE;
v_hostname = g_dbus_proxy_get_cached_property (priv->hostnamed_proxy,
"Hostname");
if (!v_hostname) {
_LOGT ("transient hostname retrieval failed");
return FALSE;
}
*hostname = g_variant_dup_string (v_hostname, NULL);
g_variant_unref (v_hostname);
return TRUE;
}
gboolean
nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostname)
{
NMHostnameManagerPrivate *priv;
char *hostname_eol;
gboolean ret;
gs_free_error GError *error = NULL;
const char *file = HOSTNAME_FILE;
gs_free char *link_path = NULL;
gs_unref_variant GVariant *var = NULL;
struct stat file_stat;
#if HAVE_SELINUX
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
mode_t st_mode = 0;
#endif
g_return_val_if_fail (NM_IS_HOSTNAME_MANAGER (self), FALSE);
priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
if (priv->hostnamed_proxy) {
var = g_dbus_proxy_call_sync (priv->hostnamed_proxy,
"SetStaticHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (error)
_LOGW ("could not set hostname: %s", error->message);
return !error;
}
/* If the hostname file is a symbolic link, follow it to find where the
* real file is located, otherwise g_file_set_contents will attempt to
* replace the link with a plain file.
*/
if ( lstat (file, &file_stat) == 0
&& S_ISLNK (file_stat.st_mode)
&& (link_path = nm_utils_read_link_absolute (file, NULL)))
file = link_path;
#if HAVE_SELINUX
/* Get default context for hostname file and set it for fscreate */
if (stat (file, &file_stat) == 0)
st_mode = file_stat.st_mode;
matchpathcon (file, st_mode, &se_ctx);
matchpathcon_fini ();
getfscreatecon (&se_ctx_prev);
setfscreatecon (se_ctx);
#endif
#if defined (HOSTNAME_PERSIST_GENTOO)
hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n"
"hostname=\"%s\"\n", hostname);
#else
hostname_eol = g_strdup_printf ("%s\n", hostname);
#endif
ret = g_file_set_contents (file, hostname_eol, -1, &error);
#if HAVE_SELINUX
/* Restore previous context and cleanup */
setfscreatecon (se_ctx_prev);
freecon (se_ctx);
freecon (se_ctx_prev);
#endif
g_free (hostname_eol);
if (!ret) {
_LOGW ("could not save hostname to %s: %s", file, error->message);
return FALSE;
}
return TRUE;
}
gboolean
nm_hostname_manager_validate_hostname (const char *hostname)
{
const char *p;
gboolean dot = TRUE;
if (!hostname || !hostname[0])
return FALSE;
for (p = hostname; *p; p++) {
if (*p == '.') {
if (dot)
return FALSE;
dot = TRUE;
} else {
if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_'))
return FALSE;
dot = FALSE;
}
}
if (dot)
return FALSE;
return (p - hostname <= HOST_NAME_MAX);
}
static void
hostname_file_changed_cb (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
_set_hostname_read (user_data);
}
/*****************************************************************************/
static void
hostnamed_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
char **invalidated_properties,
gpointer user_data)
{
NMHostnameManager *self = user_data;
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
GVariant *v_hostname;
v_hostname = g_dbus_proxy_get_cached_property (priv->hostnamed_proxy,
"StaticHostname");
if (v_hostname) {
_set_hostname (self, g_variant_get_string (v_hostname, NULL));
g_variant_unref (v_hostname);
}
}
static void
setup_hostname_file_monitors (NMHostnameManager *self)
{
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
GFileMonitor *monitor;
const char *path = HOSTNAME_FILE;
char *link_path = NULL;
struct stat file_stat;
GFile *file;
/* resolve the path to the hostname file if it is a symbolic link */
if ( lstat(path, &file_stat) == 0
&& S_ISLNK (file_stat.st_mode)
&& (link_path = nm_utils_read_link_absolute (path, NULL))) {
path = link_path;
if ( lstat(link_path, &file_stat) == 0
&& S_ISLNK (file_stat.st_mode)) {
_LOGW ("only one level of symbolic link indirection is allowed when monitoring "
HOSTNAME_FILE);
}
}
/* monitor changes to hostname file */
file = g_file_new_for_path (path);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
g_free(link_path);
if (monitor) {
priv->monitor_id = g_signal_connect (monitor, "changed",
G_CALLBACK (hostname_file_changed_cb),
self);
priv->monitor = monitor;
}
#if defined (HOSTNAME_PERSIST_SUSE)
/* monitor changes to dhcp file to know whether the hostname is valid */
file = g_file_new_for_path (CONF_DHCP);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->dhcp_monitor_id = g_signal_connect (monitor, "changed",
G_CALLBACK (hostname_file_changed_cb),
self);
priv->dhcp_monitor = monitor;
}
#endif
_set_hostname_read (self);
}
/*****************************************************************************/
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMHostnameManager *self = NM_HOSTNAME_MANAGER (object);
switch (prop_id) {
case PROP_HOSTNAME:
g_value_set_string (value, nm_hostname_manager_get_hostname (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*****************************************************************************/
static void
nm_hostname_manager_init (NMHostnameManager *self)
{
}
static void
constructed (GObject *object)
{
NMHostnameManager *self = NM_HOSTNAME_MANAGER (object);
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
GDBusProxy *proxy;
GVariant *variant;
gs_free GError *error = NULL;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL,
HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH,
HOSTNAMED_SERVICE_INTERFACE, NULL, &error);
if (proxy) {
variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname");
if (variant) {
_LOGI ("hostname: using hostnamed");
priv->hostnamed_proxy = proxy;
g_signal_connect (proxy, "g-properties-changed",
G_CALLBACK (hostnamed_properties_changed), self);
hostnamed_properties_changed (proxy, NULL, NULL, self);
g_variant_unref (variant);
} else {
_LOGI ("hostname: couldn't get property from hostnamed");
g_object_unref (proxy);
}
} else {
_LOGI ("hostname: hostnamed not used as proxy creation failed with: %s",
error->message);
g_clear_error (&error);
}
if (!priv->hostnamed_proxy)
setup_hostname_file_monitors (self);
G_OBJECT_CLASS (nm_hostname_manager_parent_class)->constructed (object);
}
static void
dispose (GObject *object)
{
NMHostnameManager *self = NM_HOSTNAME_MANAGER (object);
NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self);
if (priv->hostnamed_proxy) {
g_signal_handlers_disconnect_by_func (priv->hostnamed_proxy,
G_CALLBACK (hostnamed_properties_changed),
self);
g_clear_object (&priv->hostnamed_proxy);
}
if (priv->monitor) {
if (priv->monitor_id)
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
g_file_monitor_cancel (priv->monitor);
g_clear_object (&priv->monitor);
}
if (priv->dhcp_monitor) {
if (priv->dhcp_monitor_id)
g_signal_handler_disconnect (priv->dhcp_monitor,
priv->dhcp_monitor_id);
g_file_monitor_cancel (priv->dhcp_monitor);
g_clear_object (&priv->dhcp_monitor);
}
nm_clear_g_free (&priv->current_hostname);
G_OBJECT_CLASS (nm_hostname_manager_parent_class)->dispose (object);
}
static void
nm_hostname_manager_class_init (NMHostnameManagerClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->dispose = dispose;
obj_properties[PROP_HOSTNAME] =
g_param_spec_string (NM_HOSTNAME_MANAGER_HOSTNAME, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
}

63
src/nm-hostname-manager.h Normal file
View file

@ -0,0 +1,63 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager
*
* Søren Sandmann <sandmann@daimi.au.dk>
* Dan Williams <dcbw@redhat.com>
* Tambet Ingo <tambet@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2011, 2017 Red Hat, Inc.
* (C) Copyright 2008 Novell, Inc.
*/
#ifndef __NM_HOSTNAME_MANAGER_H__
#define __NM_HOSTNAME_MANAGER_H__
#define NM_TYPE_HOSTNAME_MANAGER (nm_hostname_manager_get_type ())
#define NM_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManager))
#define NM_HOSTNAME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass))
#define NM_IS_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_HOSTNAME_MANAGER))
#define NM_IS_HOSTNAME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_HOSTNAME_MANAGER))
#define NM_HOSTNAME_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass))
#define NM_HOSTNAME_MANAGER_HOSTNAME "hostname"
typedef struct _NMHostnameManager NMHostnameManager;
typedef struct _NMHostnameManagerClass NMHostnameManagerClass;
typedef void (*NMHostnameManagerSetHostnameCb) (const char *name, gboolean result, gpointer user_data);
GType nm_hostname_manager_get_type (void);
NMHostnameManager *nm_hostname_manager_get (void);
const char *nm_hostname_manager_get_hostname (NMHostnameManager *self);
char *nm_hostname_manager_read_hostname (NMHostnameManager *self);
gboolean nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostname);
void nm_hostname_manager_set_transient_hostname (NMHostnameManager *self,
const char *hostname,
NMHostnameManagerSetHostnameCb cb,
gpointer user_data);
gboolean nm_hostname_manager_get_transient_hostname (NMHostnameManager *self,
char **hostname);
gboolean nm_hostname_manager_validate_hostname (const char *hostname);
#endif /* __NM_HOSTNAME_MANAGER_H__ */

View file

@ -35,6 +35,7 @@
#include "devices/nm-device.h"
#include "devices/nm-device-generic.h"
#include "platform/nm-platform.h"
#include "nm-hostname-manager.h"
#include "nm-rfkill-manager.h"
#include "dhcp/nm-dhcp-manager.h"
#include "settings/nm-settings.h"
@ -122,6 +123,8 @@ typedef struct {
NMPolicy *policy;
NMHostnameManager *hostname_manager;
NMBusManager *dbus_mgr;
struct {
GDBusConnection *connection;
@ -132,7 +135,6 @@ typedef struct {
NMCheckpointManager *checkpoint_mgr;
NMSettings *settings;
char *hostname;
RadioState radio_states[RFKILL_TYPE_MAX];
NMVpnManager *vpn_manager;
@ -211,7 +213,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMManager,
PROP_ALL_DEVICES,
/* Not exported */
PROP_HOSTNAME,
PROP_SLEEPING,
);
@ -1404,35 +1405,17 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
}
static void
system_hostname_changed_cb (NMSettings *settings,
GParamSpec *pspec,
gpointer user_data)
hostname_changed_cb (NMHostnameManager *hostname_manager,
GParamSpec *pspec,
NMManager *self)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
char *hostname;
const char *hostname;
hostname = nm_settings_get_hostname (priv->settings);
hostname = nm_hostname_manager_get_hostname (priv->hostname_manager);
/* nm_settings_get_hostname() does not return an empty hostname. */
nm_assert (!hostname || *hostname);
if (!hostname && !priv->hostname)
return;
if (hostname && priv->hostname && !strcmp (hostname, priv->hostname)) {
g_free (hostname);
return;
}
/* realloc, to free possibly trailing data after NUL. */
if (hostname)
hostname = g_realloc (hostname, strlen (hostname) + 1);
g_free (priv->hostname);
priv->hostname = hostname;
_notify (self, PROP_HOSTNAME);
nm_dhcp_manager_set_default_hostname (nm_dhcp_manager_get (), priv->hostname);
nm_dispatcher_call_hostname (NULL, NULL, NULL);
nm_dhcp_manager_set_default_hostname (nm_dhcp_manager_get (), hostname);
}
/*****************************************************************************/
@ -5087,7 +5070,7 @@ nm_manager_start (NMManager *self, GError **error)
priv->net_enabled ? "enabled" : "disabled");
system_unmanaged_devices_changed_cb (priv->settings, NULL, self);
system_hostname_changed_cb (priv->settings, NULL, self);
hostname_changed_cb (priv->hostname_manager, NULL, self);
/* Start device factories */
nm_device_factory_manager_load_factories (_register_device_factory, self);
@ -5983,12 +5966,15 @@ constructed (GObject *object)
G_CALLBACK (settings_startup_complete_changed), self);
g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS,
G_CALLBACK (system_unmanaged_devices_changed_cb), self);
g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
G_CALLBACK (system_hostname_changed_cb), self);
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
G_CALLBACK (connection_added_cb), self);
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
G_CALLBACK (connection_updated_cb), self);
priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME,
G_CALLBACK (hostname_changed_cb), self);
/*
* Do not delete existing virtual devices to keep connectivity up.
* Virtual devices are reused when NetworkManager is restarted.
@ -6185,9 +6171,6 @@ get_property (GObject *object, guint prop_id,
case PROP_ACTIVATING_CONNECTION:
nm_utils_g_value_set_object_path (value, priv->activating_connection);
break;
case PROP_HOSTNAME:
g_value_set_string (value, priv->hostname);
break;
case PROP_SLEEPING:
g_value_set_boolean (value, priv->sleeping);
break;
@ -6296,8 +6279,6 @@ dispose (GObject *object)
g_clear_object (&priv->config);
}
g_free (priv->hostname);
if (priv->policy) {
g_signal_handlers_disconnect_by_func (priv->policy, policy_default_device_changed, manager);
g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_device_changed, manager);
@ -6307,12 +6288,16 @@ dispose (GObject *object)
if (priv->settings) {
g_signal_handlers_disconnect_by_func (priv->settings, settings_startup_complete_changed, manager);
g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, manager);
g_signal_handlers_disconnect_by_func (priv->settings, system_hostname_changed_cb, manager);
g_signal_handlers_disconnect_by_func (priv->settings, connection_added_cb, manager);
g_signal_handlers_disconnect_by_func (priv->settings, connection_updated_cb, manager);
g_clear_object (&priv->settings);
}
if (priv->hostname_manager) {
g_signal_handlers_disconnect_by_func (priv->hostname_manager, hostname_changed_cb, manager);
g_clear_object (&priv->hostname_manager);
}
g_clear_object (&priv->vpn_manager);
/* Unregister property filter */
@ -6474,13 +6459,6 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
/* Hostname is not exported over D-Bus */
obj_properties[PROP_HOSTNAME] =
g_param_spec_string (NM_MANAGER_HOSTNAME, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
/* Sleeping is not exported over D-Bus */
obj_properties[PROP_SLEEPING] =
g_param_spec_boolean (NM_MANAGER_SLEEPING, "", "",

View file

@ -54,7 +54,6 @@
#define NM_MANAGER_ALL_DEVICES "all-devices"
/* Not exported */
#define NM_MANAGER_HOSTNAME "hostname"
#define NM_MANAGER_SLEEPING "sleeping"
/* signals */

View file

@ -49,6 +49,7 @@
#include "nm-dhcp6-config.h"
#include "nm-config.h"
#include "nm-netns.h"
#include "nm-hostname-manager.h"
/*****************************************************************************/
@ -73,12 +74,17 @@ typedef struct {
NMSettings *settings;
NMHostnameManager *hostname_manager;
NMDevice *default_device4, *activating_device4;
NMDevice *default_device6, *activating_device6;
GResolver *resolver;
GInetAddress *lookup_addr;
GCancellable *lookup_cancellable;
struct {
GInetAddress *addr;
GResolver *resolver;
GCancellable *cancellable;
} lookup;
NMDnsManager *dns_manager;
gulong config_changed_id;
@ -443,50 +449,46 @@ settings_set_hostname_cb (const char *hostname,
#define HOST_NAME_BUFSIZE (HOST_NAME_MAX + 2)
static char *
_get_hostname (NMPolicy *self, char **hostname)
_get_hostname (NMPolicy *self)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
char *buf;
g_assert (hostname && *hostname == NULL);
char *hostname = NULL;
/* If there is an in-progress hostname change, return
* the last hostname set as would be set soon...
*/
if (priv->changing_hostname) {
_LOGT (LOGD_DNS, "get-hostname: \"%s\" (last on set)", priv->last_hostname);
*hostname = g_strdup (priv->last_hostname);
return *hostname;
return g_strdup (priv->last_hostname);
}
/* try to get the hostname via dbus... */
if (nm_settings_get_transient_hostname (priv->settings, hostname)) {
_LOGT (LOGD_DNS, "get-hostname: \"%s\" (from dbus)", *hostname);
return *hostname;
if (nm_hostname_manager_get_transient_hostname (priv->hostname_manager, &hostname)) {
_LOGT (LOGD_DNS, "get-hostname: \"%s\" (from dbus)", hostname);
return hostname;
}
/* ...or retrieve it by yourself */
buf = g_malloc (HOST_NAME_BUFSIZE);
if (gethostname (buf, HOST_NAME_BUFSIZE -1) != 0) {
hostname = g_malloc (HOST_NAME_BUFSIZE);
if (gethostname (hostname, HOST_NAME_BUFSIZE -1) != 0) {
int errsv = errno;
_LOGT (LOGD_DNS, "get-hostname: couldn't get the system hostname: (%d) %s",
errsv, g_strerror (errsv));
g_free (buf);
g_free (hostname);
return NULL;
}
/* the name may be truncated... */
buf[HOST_NAME_BUFSIZE - 1] = '\0';
if (strlen (buf) >= HOST_NAME_BUFSIZE -1) {
_LOGT (LOGD_DNS, "get-hostname: system hostname too long: \"%s\"", buf);
g_free (buf);
hostname[HOST_NAME_BUFSIZE - 1] = '\0';
if (strlen (hostname) >= HOST_NAME_BUFSIZE -1) {
_LOGT (LOGD_DNS, "get-hostname: system hostname too long: \"%s\"", hostname);
g_free (hostname);
return NULL;
}
_LOGT (LOGD_DNS, "get-hostname: \"%s\"", buf);
*hostname = buf;
return *hostname;
_LOGT (LOGD_DNS, "get-hostname: \"%s\"", hostname);
return hostname;
}
static void
@ -508,7 +510,7 @@ _set_hostname (NMPolicy *self,
* restart the reverse lookup thread later.
*/
if (new_hostname)
g_clear_object (&priv->lookup_addr);
g_clear_object (&priv->lookup.addr);
/* Update the DNS only if the hostname is actually
* going to change.
@ -534,7 +536,7 @@ _set_hostname (NMPolicy *self,
name = new_hostname;
/* Don't set the hostname if it isn't actually changing */
if ( _get_hostname (self, &old_hostname)
if ( (old_hostname = _get_hostname (self))
&& (nm_streq (name, old_hostname))) {
_LOGT (LOGD_DNS, "set-hostname: hostname already set to '%s' (%s)", name, msg);
return;
@ -549,10 +551,10 @@ _set_hostname (NMPolicy *self,
/* Ask NMSettings to update the transient hostname using its
* systemd-hostnamed proxy */
nm_settings_set_transient_hostname (priv->settings,
name,
settings_set_hostname_cb,
g_object_ref (self));
nm_hostname_manager_set_transient_hostname (priv->hostname_manager,
name,
settings_set_hostname_cb,
g_object_ref (self));
}
static void
@ -572,7 +574,7 @@ lookup_callback (GObject *source,
self = user_data;
priv = NM_POLICY_GET_PRIVATE (self);
g_clear_object (&priv->lookup_cancellable);
g_clear_object (&priv->lookup.cancellable);
if (hostname)
_set_hostname (self, hostname, "from address lookup");
@ -580,11 +582,24 @@ lookup_callback (GObject *source,
_set_hostname (self, NULL, error->message);
}
static void
lookup_by_address (NMPolicy *self)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
nm_clear_g_cancellable (&priv->lookup.cancellable);
priv->lookup.cancellable = g_cancellable_new ();
g_resolver_lookup_by_address_async (priv->lookup.resolver,
priv->lookup.addr,
priv->lookup.cancellable,
lookup_callback, self);
}
static void
update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const char *msg)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
char *configured_hostname = NULL;
const char *configured_hostname;
gs_free char *temp_hostname = NULL;
const char *dhcp_hostname, *p;
NMIP4Config *ip4_config;
@ -600,12 +615,12 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const
_LOGT (LOGD_DNS, "set-hostname: updating hostname (%s)", msg);
nm_clear_g_cancellable (&priv->lookup_cancellable);
nm_clear_g_cancellable (&priv->lookup.cancellable);
/* Check if the hostname was set externally to NM, so that in that case
* we can avoid to fallback to the one we got when we started.
* Consider "not specific" hostnames as equal. */
if ( _get_hostname (self, &temp_hostname)
if ( (temp_hostname = _get_hostname (self))
&& !nm_streq0 (temp_hostname, priv->last_hostname)
&& ( nm_utils_is_specific_hostname (temp_hostname)
|| nm_utils_is_specific_hostname (priv->last_hostname))) {
@ -614,14 +629,14 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const
temp_hostname);
priv->dhcp_hostname = FALSE;
if (!nm_utils_is_specific_hostname (temp_hostname))
nm_clear_g_free (&temp_hostname);
if (!nm_streq0 (temp_hostname, priv->orig_hostname)) {
/* Update original (fallback) hostname */
g_free (priv->orig_hostname);
if (nm_utils_is_specific_hostname (temp_hostname)) {
priv->orig_hostname = temp_hostname;
temp_hostname = NULL;
} else
priv->orig_hostname = NULL;
priv->orig_hostname = g_steal_pointer (&temp_hostname);
_LOGT (LOGD_DNS, "hostname-original: update to %s%s%s",
NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname));
}
}
@ -635,14 +650,12 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const
*/
/* Try a persistent hostname first */
g_object_get (G_OBJECT (priv->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL);
configured_hostname = nm_hostname_manager_get_hostname (priv->hostname_manager);
if (configured_hostname && nm_utils_is_specific_hostname (configured_hostname)) {
_set_hostname (self, configured_hostname, "from system configuration");
priv->dhcp_hostname = FALSE;
g_free (configured_hostname);
return;
}
g_free (configured_hostname);
/* Try automatically determined hostname from the best device's IP config */
if (!best4)
@ -737,15 +750,15 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const
const NMPlatformIP4Address *addr4;
addr4 = nm_ip4_config_get_address (ip4_config, 0);
g_clear_object (&priv->lookup_addr);
priv->lookup_addr = g_inet_address_new_from_bytes ((guint8 *) &addr4->address,
g_clear_object (&priv->lookup.addr);
priv->lookup.addr = g_inet_address_new_from_bytes ((guint8 *) &addr4->address,
G_SOCKET_FAMILY_IPV4);
} else if (ip6_config && nm_ip6_config_get_num_addresses (ip6_config) > 0) {
const NMPlatformIP6Address *addr6;
addr6 = nm_ip6_config_get_address (ip6_config, 0);
g_clear_object (&priv->lookup_addr);
priv->lookup_addr = g_inet_address_new_from_bytes ((guint8 *) &addr6->address,
g_clear_object (&priv->lookup.addr);
priv->lookup.addr = g_inet_address_new_from_bytes ((guint8 *) &addr6->address,
G_SOCKET_FAMILY_IPV6);
} else {
/* No valid IP config; fall back to localhost.localdomain */
@ -753,11 +766,7 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const
return;
}
priv->lookup_cancellable = g_cancellable_new ();
g_resolver_lookup_by_address_async (priv->resolver,
priv->lookup_addr,
priv->lookup_cancellable,
lookup_callback, self);
lookup_by_address (self);
}
static void
@ -1248,7 +1257,7 @@ process_secondaries (NMPolicy *self,
}
static void
hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data)
hostname_changed (NMHostnameManager *hostname_manager, GParamSpec *pspec, gpointer user_data)
{
NMPolicyPrivate *priv = user_data;
NMPolicy *self = _PRIV_TO_SELF (priv);
@ -2088,30 +2097,26 @@ dns_config_changed (NMDnsManager *dns_manager, gpointer user_data)
* (race in updating DNS and doing the reverse lookup).
*/
nm_clear_g_cancellable (&priv->lookup_cancellable);
nm_clear_g_cancellable (&priv->lookup.cancellable);
/* Re-start the hostname lookup thread if we don't have hostname yet. */
if (priv->lookup_addr) {
if (priv->lookup.addr) {
char *str = NULL;
gs_free char *hostname = NULL;
/* Check if the hostname was externally set */
if ( _get_hostname (self, &hostname)
if ( (hostname = _get_hostname (self))
&& nm_utils_is_specific_hostname (hostname)
&& !nm_streq0 (hostname, priv->last_hostname)) {
g_clear_object (&priv->lookup_addr);
g_clear_object (&priv->lookup.addr);
return;
}
_LOGD (LOGD_DNS, "restarting reverse-lookup thread for address %s",
(str = g_inet_address_to_string (priv->lookup_addr)));
(str = g_inet_address_to_string (priv->lookup.addr)));
g_free (str);
priv->lookup_cancellable = g_cancellable_new ();
g_resolver_lookup_by_address_async (priv->resolver,
priv->lookup_addr,
priv->lookup_cancellable,
lookup_callback, self);
lookup_by_address (self);
}
}
@ -2240,6 +2245,15 @@ nm_policy_get_activating_ip6_device (NMPolicy *self)
/*****************************************************************************/
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_hostname_mode_to_string, NMPolicyHostnameMode,
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_NONE, "none"),
NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_DHCP, "dhcp"),
NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_FULL, "full"),
);
/*****************************************************************************/
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
@ -2300,6 +2314,8 @@ nm_policy_init (NMPolicy *self)
priv->netns = g_object_ref (nm_netns_get ());
priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
hostname_mode = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
NM_CONFIG_KEYFILE_GROUP_MAIN,
NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE,
@ -2311,7 +2327,6 @@ nm_policy_init (NMPolicy *self)
else /* default - full mode */
priv->hostname_mode = NM_POLICY_HOSTNAME_MODE_FULL;
_LOGI (LOGD_DNS, "hostname management mode: %s", hostname_mode ? hostname_mode : "default");
priv->devices = g_hash_table_new (NULL, NULL);
priv->ip6_prefix_delegations = g_array_new (FALSE, FALSE, sizeof (IP6PrefixDelegation));
g_array_set_clear_func (priv->ip6_prefix_delegations, clear_ip6_prefix_delegation);
@ -2325,7 +2340,7 @@ constructed (GObject *object)
char *hostname = NULL;
/* Grab hostname on startup and use that if nothing provides one */
if (_get_hostname (self, &hostname)) {
if ((hostname = _get_hostname (self))) {
/* init last_hostname */
priv->last_hostname = hostname;
@ -2333,6 +2348,8 @@ constructed (GObject *object)
if (nm_utils_is_specific_hostname (hostname))
priv->orig_hostname = g_strdup (hostname);
}
_LOGT (LOGD_DNS, "hostname-original: set to %s%s%s",
NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname));
priv->firewall_manager = g_object_ref (nm_firewall_manager_get ());
g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED,
@ -2343,9 +2360,10 @@ constructed (GObject *object)
priv->config_changed_id = g_signal_connect (priv->dns_manager, NM_DNS_MANAGER_CONFIG_CHANGED,
G_CALLBACK (dns_config_changed), self);
priv->resolver = g_resolver_get_default ();
priv->lookup.resolver = g_resolver_get_default ();
g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME, (GCallback) hostname_changed, priv);
g_signal_connect (priv->manager, "notify::" NM_MANAGER_HOSTNAME, (GCallback) hostname_changed, priv);
g_signal_connect (priv->manager, "notify::" NM_MANAGER_SLEEPING, (GCallback) sleeping_changed, priv);
g_signal_connect (priv->manager, "notify::" NM_MANAGER_NETWORKING_ENABLED, (GCallback) sleeping_changed, priv);
g_signal_connect (priv->manager, NM_MANAGER_INTERNAL_DEVICE_ADDED, (GCallback) device_added, priv);
@ -2360,6 +2378,8 @@ constructed (GObject *object)
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, (GCallback) secret_agent_registered, priv);
G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object);
_LOGD (LOGD_DNS, "hostname-mode: %s", _hostname_mode_to_string (priv->hostname_mode));
}
NMPolicy *
@ -2383,10 +2403,9 @@ dispose (GObject *object)
GHashTableIter h_iter;
NMDevice *device;
nm_clear_g_cancellable (&priv->lookup_cancellable);
g_clear_object (&priv->lookup_addr);
g_clear_object (&priv->resolver);
nm_clear_g_cancellable (&priv->lookup.cancellable);
g_clear_object (&priv->lookup.addr);
g_clear_object (&priv->lookup.resolver);
while (priv->pending_activation_checks)
activate_data_free (priv->pending_activation_checks->data);
@ -2424,6 +2443,11 @@ dispose (GObject *object)
g_clear_pointer (&priv->cur_hostname, g_free);
g_clear_pointer (&priv->last_hostname, g_free);
if (priv->hostname_manager) {
g_signal_handlers_disconnect_by_data (priv->hostname_manager, priv);
g_clear_object (&priv->hostname_manager);
}
if (priv->settings) {
g_signal_handlers_disconnect_by_data (priv->settings, priv);
g_clear_object (&priv->settings);

View file

@ -76,6 +76,7 @@
#include "NetworkManagerUtils.h"
#include "nm-dispatcher.h"
#include "nm-inotify-helper.h"
#include "nm-hostname-manager.h"
#include "introspection/org.freedesktop.NetworkManager.Settings.h"
@ -94,13 +95,6 @@ EXPORT(nm_settings_connection_replace_and_commit)
/*****************************************************************************/
#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1"
#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1"
#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1"
#define HOSTNAME_FILE_DEFAULT "/etc/hostname"
#define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME"
#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname"
#define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
#define CONF_DHCP IFCFG_DIR "/dhcp"
@ -162,14 +156,8 @@ typedef struct {
gboolean started;
gboolean startup_complete;
struct {
char *value;
GFileMonitor *monitor;
GFileMonitor *dhcp_monitor;
gulong monitor_id;
gulong dhcp_monitor_id;
GDBusProxy *hostnamed_proxy;
} hostname;
NMHostnameManager *hostname_manager;
} NMSettingsPrivate;
struct _NMSettings {
@ -568,131 +556,6 @@ get_plugin (NMSettings *self, guint32 capability)
return NULL;
}
#if defined(HOSTNAME_PERSIST_GENTOO)
static gchar *
read_hostname_gentoo (const char *path)
{
gs_free char *contents = NULL;
gs_strfreev char **all_lines = NULL;
const char *tmp;
guint i;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
for (i = 0; all_lines[i]; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
if (g_str_has_prefix (all_lines[i], "hostname=")) {
tmp = &all_lines[i][NM_STRLEN ("hostname=")];
return g_shell_unquote (tmp, NULL);
}
}
return NULL;
}
#endif
#if defined(HOSTNAME_PERSIST_SLACKWARE)
static gchar *
read_hostname_slackware (const char *path)
{
gs_free char *contents = NULL;
gs_strfreev char **all_lines = NULL;
char *tmp;
guint i, j = 0;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
for (i = 0; all_lines[i]; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
tmp = &all_lines[i][0];
/* We only want up to the first '.' -- the rest of the */
/* fqdn is defined in /etc/hosts */
while (tmp[j] != '\0') {
if (tmp[j] == '.') {
tmp[j] = '\0';
break;
}
j++;
}
return g_shell_unquote (tmp, NULL);
}
return NULL;
}
#endif
#if defined(HOSTNAME_PERSIST_SUSE)
static gboolean
hostname_is_dynamic (void)
{
GIOChannel *channel;
char *str = NULL;
gboolean dynamic = FALSE;
channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
if (!channel)
return dynamic;
while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
if (str) {
g_strstrip (str);
if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME="))
dynamic = strcmp (&str[NM_STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
g_free (str);
}
}
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return dynamic;
}
#endif
/* Returns an allocated string which the caller owns and must eventually free */
char *
nm_settings_get_hostname (NMSettings *self)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
char *hostname = NULL;
if (!priv->started)
return NULL;
if (priv->hostname.hostnamed_proxy) {
hostname = g_strdup (priv->hostname.value);
goto out;
}
#if defined(HOSTNAME_PERSIST_SUSE)
if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ())
return NULL;
#endif
#if defined(HOSTNAME_PERSIST_GENTOO)
hostname = read_hostname_gentoo (HOSTNAME_FILE);
#elif defined(HOSTNAME_PERSIST_SLACKWARE)
hostname = read_hostname_slackware (HOSTNAME_FILE);
#else
if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL))
g_strchomp (hostname);
#endif
out:
if (hostname && !hostname[0]) {
g_free (hostname);
hostname = NULL;
}
return hostname;
}
static gboolean
find_spec (GSList *spec_list, const char *spec)
{
@ -1626,160 +1489,7 @@ impl_settings_reload_connections (NMSettings *self,
g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE));
}
typedef struct {
char *hostname;
NMSettingsSetHostnameCb cb;
gpointer user_data;
} SetHostnameInfo;
static void
set_transient_hostname_done (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GDBusProxy *proxy = G_DBUS_PROXY (object);
gs_free SetHostnameInfo *info = user_data;
gs_unref_variant GVariant *result = NULL;
gs_free_error GError *error = NULL;
result = g_dbus_proxy_call_finish (proxy, res, &error);
if (error) {
_LOGW ("couldn't set the system hostname to '%s' using hostnamed: %s",
info->hostname, error->message);
}
info->cb (info->hostname, !error, info->user_data);
g_free (info->hostname);
}
void
nm_settings_set_transient_hostname (NMSettings *self,
const char *hostname,
NMSettingsSetHostnameCb cb,
gpointer user_data)
{
NMSettingsPrivate *priv;
SetHostnameInfo *info;
g_return_if_fail (NM_IS_SETTINGS (self));
priv = NM_SETTINGS_GET_PRIVATE (self);
if (!priv->hostname.hostnamed_proxy) {
cb (hostname, FALSE, user_data);
return;
}
info = g_new0 (SetHostnameInfo, 1);
info->hostname = g_strdup (hostname);
info->cb = cb;
info->user_data = user_data;
g_dbus_proxy_call (priv->hostname.hostnamed_proxy,
"SetHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
set_transient_hostname_done,
info);
}
gboolean
nm_settings_get_transient_hostname (NMSettings *self, char **hostname)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GVariant *v_hostname;
if (!priv->hostname.hostnamed_proxy)
return FALSE;
v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy,
"Hostname");
if (!v_hostname) {
_LOGT ("transient hostname retrieval failed");
return FALSE;
}
*hostname = g_variant_dup_string (v_hostname, NULL);
g_variant_unref (v_hostname);
return TRUE;
}
static gboolean
write_hostname (NMSettingsPrivate *priv, const char *hostname)
{
char *hostname_eol;
gboolean ret;
gs_free_error GError *error = NULL;
const char *file = HOSTNAME_FILE;
gs_free char *link_path = NULL;
gs_unref_variant GVariant *var = NULL;
struct stat file_stat;
#if HAVE_SELINUX
security_context_t se_ctx_prev = NULL, se_ctx = NULL;
mode_t st_mode = 0;
#endif
if (priv->hostname.hostnamed_proxy) {
var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy,
"SetStaticHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (error)
_LOGW ("could not set hostname: %s", error->message);
return !error;
}
/* If the hostname file is a symbolic link, follow it to find where the
* real file is located, otherwise g_file_set_contents will attempt to
* replace the link with a plain file.
*/
if ( lstat (file, &file_stat) == 0
&& S_ISLNK (file_stat.st_mode)
&& (link_path = nm_utils_read_link_absolute (file, NULL)))
file = link_path;
#if HAVE_SELINUX
/* Get default context for hostname file and set it for fscreate */
if (stat (file, &file_stat) == 0)
st_mode = file_stat.st_mode;
matchpathcon (file, st_mode, &se_ctx);
matchpathcon_fini ();
getfscreatecon (&se_ctx_prev);
setfscreatecon (se_ctx);
#endif
#if defined (HOSTNAME_PERSIST_GENTOO)
hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n"
"hostname=\"%s\"\n", hostname);
#else
hostname_eol = g_strdup_printf ("%s\n", hostname);
#endif
ret = g_file_set_contents (file, hostname_eol, -1, &error);
#if HAVE_SELINUX
/* Restore previous context and cleanup */
setfscreatecon (se_ctx_prev);
freecon (se_ctx);
freecon (se_ctx_prev);
#endif
g_free (hostname_eol);
if (!ret) {
_LOGW ("could not save hostname to %s: %s", file, error->message);
return FALSE;
}
return TRUE;
}
/*****************************************************************************/
static void
pk_hostname_cb (NMAuthChain *chain,
@ -1812,7 +1522,7 @@ pk_hostname_cb (NMAuthChain *chain,
} else {
hostname = nm_auth_chain_get_data (chain, "hostname");
if (!write_hostname (priv, hostname)) {
if (!nm_hostname_manager_write_hostname (priv->hostname_manager, hostname)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_FAILED,
"Saving the hostname failed.");
@ -1827,33 +1537,6 @@ pk_hostname_cb (NMAuthChain *chain,
nm_auth_chain_unref (chain);
}
static gboolean
validate_hostname (const char *hostname)
{
const char *p;
gboolean dot = TRUE;
if (!hostname || !hostname[0])
return FALSE;
for (p = hostname; *p; p++) {
if (*p == '.') {
if (dot)
return FALSE;
dot = TRUE;
} else {
if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_'))
return FALSE;
dot = FALSE;
}
}
if (dot)
return FALSE;
return (p - hostname <= HOST_NAME_MAX);
}
static void
impl_settings_save_hostname (NMSettings *self,
GDBusMethodInvocation *context,
@ -1864,7 +1547,7 @@ impl_settings_save_hostname (NMSettings *self,
GError *error = NULL;
/* Minimal validation of the hostname */
if (!validate_hostname (hostname)) {
if (!nm_hostname_manager_validate_hostname (hostname)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_HOSTNAME,
"The hostname was too long or contained invalid characters.");
@ -1888,37 +1571,7 @@ done:
g_dbus_method_invocation_take_error (context, error);
}
static void
hostname_maybe_changed (NMSettings *settings)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings);
char *new_hostname;
new_hostname = nm_settings_get_hostname (settings);
if ( (new_hostname && !priv->hostname.value)
|| (!new_hostname && priv->hostname.value)
|| (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) {
_LOGI ("hostname changed from %s%s%s to %s%s%s",
NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)"));
g_free (priv->hostname.value);
priv->hostname.value = new_hostname;
_notify (settings, PROP_HOSTNAME);
} else
g_free (new_hostname);
}
static void
hostname_file_changed_cb (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
hostname_maybe_changed (user_data);
}
/*****************************************************************************/
static gboolean
have_connection_for_device (NMSettings *self, NMDevice *device)
@ -2141,95 +1794,19 @@ nm_settings_get_startup_complete (NMSettings *self)
/*****************************************************************************/
static void
hostnamed_properties_changed (GDBusProxy *proxy,
GVariant *changed_properties,
char **invalidated_properties,
gpointer user_data)
_hostname_changed_cb (NMHostnameManager *hostname_manager,
GParamSpec *pspec,
gpointer user_data)
{
NMSettings *self = user_data;
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GVariant *v_hostname;
const char *hostname;
v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy,
"StaticHostname");
if (!v_hostname)
return;
hostname = g_variant_get_string (v_hostname, NULL);
if (g_strcmp0 (priv->hostname.value, hostname) != 0) {
_LOGI ("hostname changed from %s%s%s to %s%s%s",
NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
g_free (priv->hostname.value);
priv->hostname.value = g_strdup (hostname);
_notify (self, PROP_HOSTNAME);
nm_dispatcher_call_hostname (NULL, NULL, NULL);
}
g_variant_unref (v_hostname);
_notify (user_data, PROP_HOSTNAME);
}
static void
setup_hostname_file_monitors (NMSettings *self)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GFileMonitor *monitor;
const char *path = HOSTNAME_FILE;
char *link_path = NULL;
struct stat file_stat;
GFile *file;
priv->hostname.value = nm_settings_get_hostname (self);
/* resolve the path to the hostname file if it is a symbolic link */
if ( lstat(path, &file_stat) == 0
&& S_ISLNK (file_stat.st_mode)
&& (link_path = nm_utils_read_link_absolute (path, NULL))) {
path = link_path;
if ( lstat(link_path, &file_stat) == 0
&& S_ISLNK (file_stat.st_mode)) {
_LOGW ("only one level of symbolic link indirection is allowed when monitoring "
HOSTNAME_FILE);
}
}
/* monitor changes to hostname file */
file = g_file_new_for_path (path);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
g_free(link_path);
if (monitor) {
priv->hostname.monitor_id = g_signal_connect (monitor, "changed",
G_CALLBACK (hostname_file_changed_cb),
self);
priv->hostname.monitor = monitor;
}
#if defined (HOSTNAME_PERSIST_SUSE)
/* monitor changes to dhcp file to know whether the hostname is valid */
file = g_file_new_for_path (CONF_DHCP);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed",
G_CALLBACK (hostname_file_changed_cb),
self);
priv->hostname.dhcp_monitor = monitor;
}
#endif
hostname_maybe_changed (self);
}
/*****************************************************************************/
gboolean
nm_settings_start (NMSettings *self, GError **error)
{
NMSettingsPrivate *priv;
GDBusProxy *proxy;
GVariant *variant;
GError *local_error = NULL;
gs_strfreev char **plugins = NULL;
priv = NM_SETTINGS_GET_PRIVATE (self);
@ -2245,33 +1822,14 @@ nm_settings_start (NMSettings *self, GError **error)
load_connections (self);
check_startup_complete (self);
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL,
HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH,
HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error);
if (proxy) {
variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname");
if (variant) {
_LOGI ("hostname: using hostnamed");
priv->hostname.hostnamed_proxy = proxy;
g_signal_connect (proxy, "g-properties-changed",
G_CALLBACK (hostnamed_properties_changed), self);
hostnamed_properties_changed (proxy, NULL, NULL, self);
g_variant_unref (variant);
} else {
_LOGI ("hostname: couldn't get property from hostnamed");
g_object_unref (proxy);
}
} else {
_LOGI ("hostname: hostnamed not used as proxy creation failed with: %s",
local_error->message);
g_clear_error (&local_error);
}
priv->hostname_manager = g_object_ref (nm_hostname_manager_get ());
g_signal_connect (priv->hostname_manager,
"notify::"NM_HOSTNAME_MANAGER_HOSTNAME,
G_CALLBACK (_hostname_changed_cb),
self);
if (nm_hostname_manager_get_hostname (priv->hostname_manager))
_notify (self, PROP_HOSTNAME);
if (!priv->hostname.hostnamed_proxy)
setup_hostname_file_monitors (self);
priv->started = TRUE;
_notify (self, PROP_HOSTNAME);
return TRUE;
}
@ -2298,11 +1856,10 @@ get_property (GObject *object, guint prop_id,
g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
break;
case PROP_HOSTNAME:
g_value_take_string (value, nm_settings_get_hostname (self));
/* Don't ever pass NULL through D-Bus */
if (!g_value_get_string (value))
g_value_set_static_string (value, "");
g_value_set_string (value,
priv->hostname_manager
? nm_hostname_manager_get_hostname (priv->hostname_manager)
: NULL);
break;
case PROP_CAN_MODIFY:
g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS));
@ -2362,32 +1919,13 @@ dispose (GObject *object)
g_object_unref (priv->agent_mgr);
if (priv->hostname.hostnamed_proxy) {
g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy,
G_CALLBACK (hostnamed_properties_changed),
if (priv->hostname_manager) {
g_signal_handlers_disconnect_by_func (priv->hostname_manager,
G_CALLBACK (_hostname_changed_cb),
self);
g_clear_object (&priv->hostname.hostnamed_proxy);
g_clear_object (&priv->hostname_manager);
}
if (priv->hostname.monitor) {
if (priv->hostname.monitor_id)
g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id);
g_file_monitor_cancel (priv->hostname.monitor);
g_clear_object (&priv->hostname.monitor);
}
if (priv->hostname.dhcp_monitor) {
if (priv->hostname.dhcp_monitor_id)
g_signal_handler_disconnect (priv->hostname.dhcp_monitor,
priv->hostname.dhcp_monitor_id);
g_file_monitor_cancel (priv->hostname.dhcp_monitor);
g_clear_object (&priv->hostname.dhcp_monitor);
}
g_clear_pointer (&priv->hostname.value, g_free);
G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object);
}

View file

@ -119,20 +119,10 @@ gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *con
const GSList *nm_settings_get_unmanaged_specs (NMSettings *self);
char *nm_settings_get_hostname (NMSettings *self);
void nm_settings_device_added (NMSettings *self, NMDevice *device);
void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting);
gboolean nm_settings_get_startup_complete (NMSettings *self);
void nm_settings_set_transient_hostname (NMSettings *self,
const char *hostname,
NMSettingsSetHostnameCb cb,
gpointer user_data);
gboolean nm_settings_get_transient_hostname (NMSettings *self,
char **hostname);
#endif /* __NM_SETTINGS_H__ */