diff --git a/ChangeLog b/ChangeLog index 7907d7291..131a4d88c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,90 @@ +2008-09-18 Dan Williams + + Implement support for honoring configured and automatic hostnames, and for + setting the configured hostname. + + * introspection/nm-ip4-config.xml + src/nm-ip4-config.c + src/nm-ip4-config.h + src/dhcp-manager/nm-dhcp-manager.c + - Remove useless hostname property; it's not really part of the IPv4 + config + + * introspection/nm-settings-system.xml + libnm-glib/nm-dbus-settings-system.c + libnm-glib/nm-dbus-settings-system.h + - Add SetHostname() call to system settings D-Bus interface + - Add Hostname property to system settings D-Bus interface + - (nm_dbus_settings_system_save_hostname, + nm_dbus_settings_system_get_hostname): implement + + * src/nm-device.c + src/nm-device.h + - (nm_device_get_dhcp4_config): implement + + * src/nm-manager.c + src/nm-manager.h + - Fetch and track system settings service hostname changes, and proxy + the changes via a GObject property of the manager + + * system-settings/src/nm-system-config-interface.c + system-settings/src/nm-system-config-interface.h + - Replace nm_system_config_interface_supports_add() with a capabilities + bitfield + + * system-settings/src/nm-system-config-error.c + system-settings/src/nm-system-config-error.h + - Add additional errors + + * system-settings/src/dbus-settings.c + system-settings/src/dbus-settings.h + - (get_property, nm_sysconfig_settings_class_init): add hostname + property; first plugin returning a hostname wins + - (impl_settings_add_connection): use plugin capabilities instead of + nm_system_config_interface_supports_add() + - (impl_settings_save_hostname): implement hostname saving + + * src/NetworkManagerPolicy.c + - (lookup_thread_run_cb, lookup_thread_worker, lookup_thread_new, + lookup_thread_die): implement an asynchronous hostname lookup thread + which given an IPv4 address tries to look up the hostname for that + address with reverse DNS + - (get_best_device): split out best device code from + update_routing_and_dns() + - (update_etc_hosts): update /etc/hosts with the machine's new hostname + to preserve the 127.0.0.1 reverse mapping that so many things require + - (set_system_hostname): set a given hostname + - (update_system_hostname): implement hostname policy; a configured + hostname (from the system settings service) is used if available, + otherwise an automatically determined hostname from DHCP, VPN, etc. + If there was no automatically determined hostname, reverse DNS of + the best device's IP address will be used, and as a last resort the + hostname 'localhost.localdomain' is set. + - (update_routing_and_dns): use get_best_device(); update the system + hostname when the network config changes + - (hostname_changed): update system hostname if the system settings + service signals a hostname change + - (nm_policy_new): list for system settings service hostname changes + - (nm_policy_destroy): ensure that an in-progress hostname lookup thread + gets told to die + + * system-settings/plugins/keyfile/plugin.c + system-settings/plugins/ifcfg-suse/plugin.c + - (get_property, sc_plugin_ifcfg_class_init): implement hostname and + capabilities properties + + * system-settings/plugins/ifcfg-fedora/shvar.c + - (svOpenFile): re-enable R/W access of ifcfg files since the plugin + writes out /etc/sysconfig/network now + + * system-settings/plugins/ifcfg-fedora/plugin.c + - (plugin_get_hostname): get hostname from /etc/sysconfig/network + - (plugin_set_hostname): save hostname to /etc/sysconfig/network + - (sc_network_changed_cb): handle changes to /etc/sysconfig/network + - (sc_plugin_ifcfg_init): monitor /etc/sysconfig/network for changes + - (get_property, set_property, sc_plugin_ifcfg_class_init): implement + hostname get/set and capabilities get + 2008-09-18 Dan Williams * libnm-util/nm-setting-wireless.c diff --git a/introspection/nm-ip4-config.xml b/introspection/nm-ip4-config.xml index 87ad48910..120367278 100644 --- a/introspection/nm-ip4-config.xml +++ b/introspection/nm-ip4-config.xml @@ -5,9 +5,6 @@ Tuples of IPv4 address/prefix/gateway. - - The hostname associated with this IPv4 address. FIXME: what about multiple hostnames? - The nameservers in use. diff --git a/introspection/nm-settings-system.xml b/introspection/nm-settings-system.xml index 1bea6a8ba..783fa3a9c 100644 --- a/introspection/nm-settings-system.xml +++ b/introspection/nm-settings-system.xml @@ -19,6 +19,24 @@ + + + Save the hostname to persistent configuration. + + + + + The hostname to save to persistent configuration. If blank, the persistent hostname is cleared. + + + + + + + The machine hostname stored in persistent configuration. + + + The list of HAL UDIs of devices that should not be managed by NetworkManager. diff --git a/libnm-glib/nm-dbus-settings-system.c b/libnm-glib/nm-dbus-settings-system.c index 9c4fbb78c..f09b2a9ad 100644 --- a/libnm-glib/nm-dbus-settings-system.c +++ b/libnm-glib/nm-dbus-settings-system.c @@ -16,12 +16,16 @@ typedef struct { gboolean got_unmanaged_devices; GSList *unmanaged_devices; + gboolean got_hostname; + char *hostname; + gboolean disposed; } NMDBusSettingsSystemPrivate; enum { PROP_0, PROP_UNMANAGED_DEVICES, + PROP_HOSTNAME, LAST_PROP }; @@ -114,6 +118,68 @@ nm_dbus_settings_system_get_unmanaged_devices (NMDBusSettingsSystem *self) return priv->unmanaged_devices; } +gboolean +nm_dbus_settings_system_save_hostname (NMDBusSettingsSystem *self, + const char *hostname, + GError **err) +{ + NMDBusSettingsSystemPrivate *priv; + + g_return_val_if_fail (NM_IS_DBUS_SETTINGS_SYSTEM (self), FALSE); + + priv = NM_DBUS_SETTINGS_SYSTEM_GET_PRIVATE (self); + + return org_freedesktop_NetworkManagerSettings_System_save_hostname (priv->settings_proxy, hostname ? hostname : "", err); +} + +static void +update_hostname (NMDBusSettingsSystem *self, GValue *value) +{ + NMDBusSettingsSystemPrivate *priv = NM_DBUS_SETTINGS_SYSTEM_GET_PRIVATE (self); + + if (priv->hostname) { + g_free (priv->hostname); + priv->hostname = NULL; + } + + if (G_VALUE_TYPE (value) == G_TYPE_STRING) { + priv->hostname = g_value_dup_string (value); + priv->got_hostname = TRUE; + } else + g_warning ("%s: Invalid return value type: %s", __func__, G_VALUE_TYPE_NAME (value)); +} + +const char * +nm_dbus_settings_system_get_hostname (NMDBusSettingsSystem *self) +{ + NMDBusSettingsSystemPrivate *priv; + GValue value = { 0, }; + GError *err = NULL; + + g_return_val_if_fail (NM_IS_DBUS_SETTINGS_SYSTEM (self), NULL); + + priv = NM_DBUS_SETTINGS_SYSTEM_GET_PRIVATE (self); + + if (priv->got_hostname) + return priv->hostname; + + if (!dbus_g_proxy_call (priv->props_proxy, "Get", &err, + G_TYPE_STRING, NM_DBUS_SERVICE_SYSTEM_SETTINGS, + G_TYPE_STRING, "Hostname", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, + G_TYPE_INVALID)) { + g_warning ("Could not retrieve hostname: %s", err->message); + g_error_free (err); + return NULL; + } + + update_hostname (self, &value); + g_value_unset (&value); + + return priv->hostname; +} + static void proxy_properties_changed (DBusGProxy *proxy, GHashTable *properties, @@ -127,6 +193,12 @@ proxy_properties_changed (DBusGProxy *proxy, update_unmanaged_devices (self, value); g_object_notify (G_OBJECT (self), NM_DBUS_SETTINGS_SYSTEM_UNMANAGED_DEVICES); } + + value = (GValue *) g_hash_table_lookup (properties, "Hostname"); + if (value) { + update_hostname (self, value); + g_object_notify (G_OBJECT (self), NM_DBUS_SETTINGS_SYSTEM_HOSTNAME); + } } static void @@ -184,6 +256,8 @@ dispose (GObject *object) priv->disposed = TRUE; + g_free (priv->hostname); + if (priv->unmanaged_devices) { g_slist_foreach (priv->unmanaged_devices, (GFunc) g_free, NULL); g_slist_free (priv->unmanaged_devices); @@ -205,6 +279,9 @@ get_property (GObject *object, guint prop_id, case PROP_UNMANAGED_DEVICES: g_value_set_pointer (value, nm_dbus_settings_system_get_unmanaged_devices (self)); break; + case PROP_HOSTNAME: + g_value_set_string (value, nm_dbus_settings_system_get_hostname (self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -230,4 +307,13 @@ nm_dbus_settings_system_class_init (NMDBusSettingsSystemClass *dbus_settings_cla "Unmanaged devices", "Unmanaged devices", G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_HOSTNAME, + g_param_spec_string (NM_DBUS_SETTINGS_SYSTEM_HOSTNAME, + "Hostname", + "Configured hostname", + NULL, + G_PARAM_READABLE)); } + diff --git a/libnm-glib/nm-dbus-settings-system.h b/libnm-glib/nm-dbus-settings-system.h index 30146c6fb..504de1e89 100644 --- a/libnm-glib/nm-dbus-settings-system.h +++ b/libnm-glib/nm-dbus-settings-system.h @@ -15,6 +15,7 @@ G_BEGIN_DECLS #define NM_DBUS_SETTINGS_SYSTEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DBUS_SETTINGS_SYSTEM, NMDBusSettingsSystemClass)) #define NM_DBUS_SETTINGS_SYSTEM_UNMANAGED_DEVICES "unmanaged-devices" +#define NM_DBUS_SETTINGS_SYSTEM_HOSTNAME "hostname" typedef struct { NMDBusSettings parent; @@ -34,6 +35,11 @@ gboolean nm_dbus_settings_system_add_connection (NMDBusSettingsSystem *self, GSList *nm_dbus_settings_system_get_unmanaged_devices (NMDBusSettingsSystem *self); +const char *nm_dbus_settings_system_get_hostname (NMDBusSettingsSystem *self); + +gboolean nm_dbus_settings_system_save_hostname (NMDBusSettingsSystem *self, + const char *hostname, + GError **err); G_END_DECLS diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index c8fa251b1..5b472ad9f 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -17,10 +17,14 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2005 Red Hat, Inc. + * (C) Copyright 2005 - 2008 Red Hat, Inc. */ #include +#include +#include +#include +#include #include "NetworkManagerPolicy.h" #include "NetworkManagerUtils.h" @@ -40,6 +44,25 @@ #include "NetworkManagerSystem.h" #include "nm-named-manager.h" +typedef struct LookupThread LookupThread; + +typedef void (*LookupCallback) (LookupThread *thread, gpointer user_data); + +struct LookupThread { + GThread *thread; + + GMutex *lock; + gboolean die; + int ret; + + guint32 ip4_addr; + char hostname[NI_MAXHOST + 1]; + + guint done_id; + LookupCallback callback; + gpointer user_data; +}; + struct NMPolicy { NMManager *manager; guint update_state_id; @@ -48,8 +71,92 @@ struct NMPolicy { GSList *dev_signal_ids; NMDevice *default_device; + + LookupThread *lookup; }; +static gboolean +lookup_thread_run_cb (gpointer user_data) +{ + LookupThread *thread = (LookupThread *) user_data; + + (*thread->callback) (thread, thread->user_data); + return FALSE; +} + +static gpointer +lookup_thread_worker (gpointer data) +{ + LookupThread *thread = (LookupThread *) data; + struct sockaddr_in addr; + + g_mutex_lock (thread->lock); + if (thread->die) { + g_mutex_unlock (thread->lock); + return (gpointer) NULL; + } + g_mutex_unlock (thread->lock); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = thread->ip4_addr; + + thread->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in), + thread->hostname, NI_MAXHOST, NULL, 0, + NI_NAMEREQD); + if (thread->ret == 0) { + int i; + + for (i = 0; i < strlen (thread->hostname); i++) + thread->hostname[i] = tolower (thread->hostname[i]); + } + + thread->done_id = g_idle_add (lookup_thread_run_cb, thread); + return (gpointer) TRUE; +} + +static void +lookup_thread_free (LookupThread *thread) +{ + g_return_if_fail (thread != NULL); + + g_mutex_free (thread->lock); + memset (thread, 0, sizeof (LookupThread)); + g_free (thread); +} + +static LookupThread * +lookup_thread_new (guint32 ip4_addr, LookupCallback callback, gpointer user_data) +{ + LookupThread *thread; + + thread = g_malloc0 (sizeof (LookupThread)); + if (!thread) + return NULL; + + thread->lock = g_mutex_new (); + thread->callback = callback; + thread->user_data = user_data; + thread->ip4_addr = ip4_addr; + + thread->thread = g_thread_create (lookup_thread_worker, thread, FALSE, NULL); + if (!thread->thread) { + lookup_thread_free (thread); + return NULL; + } + + return thread; +} + +static void +lookup_thread_die (LookupThread *thread) +{ + g_return_if_fail (thread != NULL); + + g_mutex_lock (thread->lock); + thread->die = TRUE; + g_mutex_unlock (thread->lock); +} + #define INVALID_TAG "invalid" static const char * @@ -65,28 +172,6 @@ get_connection_id (NMConnection *connection) return s_con->id; } -static void -update_default_route (NMPolicy *policy, NMDevice *new) -{ - const char *ip_iface; - - /* FIXME: Not sure if the following makes any sense. */ - /* If iface and ip_iface are the same, it's a regular network device and we - treat it as such. However, if they differ, it's most likely something like - a serial device with ppp interface, so route all the traffic to it. */ - ip_iface = nm_device_get_ip_iface (new); - if (strcmp (ip_iface, nm_device_get_iface (new))) { - nm_system_device_replace_default_ip4_route (ip_iface, 0, 0); - } else { - NMIP4Config *config; - const NMSettingIP4Address *def_addr; - - config = nm_device_get_ip4_config (new); - def_addr = nm_ip4_config_get_address (config, 0); - nm_system_device_replace_default_ip4_route (ip_iface, def_addr->gateway, nm_ip4_config_get_mss (config)); - } -} - static guint32 get_device_priority (NMDevice *dev) { @@ -105,16 +190,19 @@ get_device_priority (NMDevice *dev) return 1; } -static void -update_routing_and_dns (NMPolicy *policy, gboolean force_update) +static NMDevice * +get_best_device (NMManager *manager, NMActRequest **out_req) { + GSList *devices, *iter; NMDevice *best = NULL; guint32 best_prio = 0; - NMActRequest *best_req = NULL; - GSList *devices, *iter; - NMNamedManager *named_mgr; - devices = nm_manager_get_devices (policy->manager); + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); + g_return_val_if_fail (out_req != NULL, NULL); + g_return_val_if_fail (*out_req == NULL, NULL); + + devices = nm_manager_get_devices (manager); for (iter = devices; iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMActRequest *req; @@ -161,10 +249,259 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) if (prio > best_prio) { best = dev; best_prio = prio; - best_req = req; + *out_req = req; } } + return best; +} + +#define FALLBACK_HOSTNAME "localhost.localdomain" + +static gboolean +update_etc_hosts (const char *hostname) +{ + char *contents = NULL; + char **lines = NULL, **line; + GError *error = NULL; + gboolean initial_comments = TRUE; + gboolean added = FALSE; + gsize contents_len = 0; + GString *new_contents; + gboolean success = FALSE; + + g_return_val_if_fail (hostname != NULL, FALSE); + + if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) { + nm_warning ("%s: couldn't read " SYSCONFDIR "/hosts: (%d) %s", + __func__, error ? error->code : 0, + (error && error->message) ? error->message : "(unknown)"); + } else { + lines = g_strsplit_set (contents, "\n\r", 0); + g_free (contents); + } + + new_contents = g_string_sized_new (contents_len ? contents_len + 100 : 200); + if (!new_contents) { + nm_warning ("%s: not enough memory to update " SYSCONFDIR "/hosts", __func__); + return FALSE; + } + + /* Replace any 127.0.0.1 entry that is at the beginning of the file or right + * after initial comments. If there is no 127.0.0.1 entry at the beginning + * or after initial comments, add one there and ignore any other 127.0.0.1 + * entries. + */ + for (line = lines; lines && *line; line++) { + gboolean add_line = TRUE; + + /* This is the first line after the initial comments */ + if (initial_comments && (*line[0] != '#')) { + initial_comments = FALSE; + g_string_append_printf (new_contents, "127.0.0.1\t%s", hostname); + if (strcmp (hostname, FALLBACK_HOSTNAME)) + g_string_append_printf (new_contents, "\t" FALLBACK_HOSTNAME); + g_string_append (new_contents, "\tlocalhost\n"); + added = TRUE; + + /* Don't add the entry if it's supposed to be the actual localhost reverse mapping */ + if (!strncmp (*line, "127.0.0.1", strlen ("127.0.0.1")) && strstr (*line, "localhost")) + add_line = FALSE; + } + + if (add_line) { + g_string_append (new_contents, *line); + g_string_append_c (new_contents, '\n'); + } + } + + /* Hmm, /etc/hosts was empty for some reason */ + if (!added) { + g_string_append (new_contents, "# Do not remove the following line, or various programs"); + g_string_append (new_contents, "# that require network functionality will fail."); + g_string_append (new_contents, "127.0.0.1\t" FALLBACK_HOSTNAME "\tlocalhost"); + } + + if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) { + nm_warning ("%s: couldn't update " SYSCONFDIR "/hosts: (%d) %s", + __func__, error ? error->code : 0, + (error && error->message) ? error->message : "(unknown)"); + } else + success = TRUE; + + g_string_free (new_contents, TRUE); + return success; +} + +static void +set_system_hostname (const char *new_hostname, const char *msg) +{ + char old_hostname[HOST_NAME_MAX + 1]; + int ret = 0; + const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME; + + old_hostname[HOST_NAME_MAX] = '\0'; + errno = 0; + ret = gethostname (old_hostname, HOST_NAME_MAX); + if (ret != 0) { + nm_warning ("%s: couldn't get the system hostname: (%d) %s", + __func__, errno, strerror (errno)); + } else { + /* Do nothing if the hostname isn't actually changing */ + if ( (new_hostname && !strcmp (old_hostname, new_hostname)) + || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME))) + return; + } + + nm_info ("Setting system hostname to '%s' (%s)", name, msg); + + ret = sethostname (name, strlen (name)); + if (ret == 0) { + if (!update_etc_hosts (name)) { + /* error updating /etc/hosts; fallback to localhost.localdomain */ + nm_info ("Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)"); + sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME)); + } + } else { + nm_warning ("%s: couldn't set the system hostname to '%s': (%d) %s", + __func__, name, errno, strerror (errno)); + } +} + +static void +lookup_callback (LookupThread *thread, gpointer user_data) +{ + NMPolicy *policy = (NMPolicy *) user_data; + + /* If the thread was told to die or it's not the current in-progress + * hostname lookup, nothing to do. + */ + if (thread->die || (thread != policy->lookup)) + goto done; + + policy->lookup = NULL; + if (!strlen (thread->hostname)) { + char *msg; + + /* No valid IP4 config (!!); fall back to localhost.localdomain */ + msg = g_strdup_printf ("address lookup failed: %d", thread->ret); + set_system_hostname (NULL, msg); + g_free (msg); + } else + set_system_hostname (thread->hostname, "from address lookup"); + +done: + lookup_thread_free (thread); +} + +static void +update_system_hostname (NMPolicy *policy, NMDevice *best) +{ + char *configured_hostname = NULL; + NMActRequest *best_req = NULL; + NMDHCP4Config *dhcp4_config; + NMIP4Config *ip4_config; + const NMSettingIP4Address *addr; + + g_return_if_fail (policy != NULL); + + if (policy->lookup) { + lookup_thread_die (policy->lookup); + policy->lookup = NULL; + } + + /* A configured hostname (via the system-settings service) overrides + * all automatic hostname determination. If there is no configured hostname, + * the best device's automatically determined hostname (from DHCP, VPN, PPP, + * etc) is used. If there is no automatically determined hostname, reverse + * DNS lookup using the best device's IP address is started to determined the + * the hostname. + */ + + /* Try a configured hostname first */ + g_object_get (G_OBJECT (policy->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL); + if (configured_hostname) { + set_system_hostname (configured_hostname, "from system configuration"); + g_free (configured_hostname); + return; + } + + /* Try automatically determined hostname from the best device's IP config */ + if (!best) + best = get_best_device (policy->manager, &best_req); + + if (!best) { + /* No best device; fall back to localhost.localdomain */ + set_system_hostname (NULL, "no default device"); + return; + } + + /* Grab a hostname out of the device's DHCP4 config */ + dhcp4_config = nm_device_get_dhcp4_config (best); + if (dhcp4_config) { + const char *dhcp4_hostname; + + dhcp4_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name"); + if (dhcp4_hostname && strlen (dhcp4_hostname)) { + set_system_hostname (dhcp4_hostname, "from DHCP"); + return; + } + } + + /* No configured hostname, no automatically determined hostname either. Start + * reverse DNS of the current IP address to try and find it. + */ + ip4_config = nm_device_get_ip4_config (best); + if ( !ip4_config + || (nm_ip4_config_get_num_nameservers (ip4_config) == 0) + || (nm_ip4_config_get_num_addresses (ip4_config) == 0)) { + /* No valid IP4 config (!!); fall back to localhost.localdomain */ + set_system_hostname (NULL, "no IPv4 config"); + return; + } + + addr = nm_ip4_config_get_address (ip4_config, 0); + g_assert (addr); /* checked for > 1 address above */ + + /* Start the hostname lookup thread */ + policy->lookup = lookup_thread_new (addr->address, lookup_callback, policy); + if (!policy->lookup) { + /* Fall back to 'localhost.localdomain' */ + set_system_hostname (NULL, "error starting hostname thread"); + } +} + +static void +update_default_route (NMPolicy *policy, NMDevice *new) +{ + const char *ip_iface; + + /* FIXME: Not sure if the following makes any sense. */ + /* If iface and ip_iface are the same, it's a regular network device and we + treat it as such. However, if they differ, it's most likely something like + a serial device with ppp interface, so route all the traffic to it. */ + ip_iface = nm_device_get_ip_iface (new); + if (strcmp (ip_iface, nm_device_get_iface (new))) { + nm_system_device_replace_default_ip4_route (ip_iface, 0, 0); + } else { + NMIP4Config *config; + const NMSettingIP4Address *def_addr; + + config = nm_device_get_ip4_config (new); + def_addr = nm_ip4_config_get_address (config, 0); + nm_system_device_replace_default_ip4_route (ip_iface, def_addr->gateway, nm_ip4_config_get_mss (config)); + } +} + +static void +update_routing_and_dns (NMPolicy *policy, gboolean force_update) +{ + NMDevice *best = NULL; + NMActRequest *best_req = NULL; + NMNamedManager *named_mgr; + GSList *devices = NULL, *iter; + + best = get_best_device (policy->manager, &best_req); if (!best) goto out; if (!force_update && (best == policy->default_device)) @@ -177,6 +514,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) * first. The order is important, we don't want two connections marked * default at the same time ever. */ + devices = nm_manager_get_devices (policy->manager); for (iter = devices; iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMActRequest *req; @@ -203,6 +541,9 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) nm_device_get_iface (best)); out: + /* Update the system hostname */ + update_system_hostname (policy, best); + policy->default_device = best; } @@ -291,6 +632,12 @@ global_state_changed (NMManager *manager, NMState state, gpointer user_data) { } +static void +hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) +{ + update_system_hostname ((NMPolicy *) user_data, NULL); +} + static void schedule_activate_check (NMPolicy *policy, NMDevice *device) { @@ -547,6 +894,10 @@ nm_policy_new (NMManager *manager) G_CALLBACK (global_state_changed), policy); policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); + id = g_signal_connect (manager, "notify::hostname", + G_CALLBACK (hostname_changed), policy); + policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); + id = g_signal_connect (manager, "device-added", G_CALLBACK (device_added), policy); policy->signal_ids = g_slist_append (policy->signal_ids, (gpointer) id); @@ -585,6 +936,14 @@ nm_policy_destroy (NMPolicy *policy) g_return_if_fail (policy != NULL); + /* Tell any existing hostname lookup thread to die, it'll get cleaned up + * by the lookup thread callback. + */ + if (policy->lookup) { + lookup_thread_die (policy->lookup); + policy->lookup = NULL; + } + for (iter = policy->pending_activation_checks; iter; iter = g_slist_next (iter)) { ActivateData *data = (ActivateData *) iter->data; diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index 97750c58f..a2e82336f 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -793,10 +793,8 @@ nm_dhcp_manager_get_ip4_config (NMDHCPManager *manager, addr = NULL; str = g_hash_table_lookup (device->options, "new_host_name"); - if (str) { - nm_ip4_config_set_hostname (ip4_config, str); + if (str) nm_info (" hostname '%s'", str); - } str = g_hash_table_lookup (device->options, "new_domain_name_servers"); if (str) { diff --git a/src/nm-device.c b/src/nm-device.c index 3aee7f9b2..0fd0909af 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1853,6 +1853,19 @@ nm_device_set_use_dhcp (NMDevice *self, } } +NMDHCP4Config * +nm_device_get_dhcp4_config (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->dhcp_manager) + return priv->dhcp4_config; + return NULL; +} NMIP4Config * nm_device_get_ip4_config (NMDevice *self) diff --git a/src/nm-device.h b/src/nm-device.h index 9412a8f09..0cb705697 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -29,6 +29,7 @@ #include "NetworkManager.h" #include "nm-activation-request.h" #include "nm-ip4-config.h" +#include "nm-dhcp4-config.h" #include "nm-connection.h" typedef enum NMActStageReturn @@ -133,6 +134,7 @@ struct in6_addr * nm_device_get_ip6_address (NMDevice *dev); gboolean nm_device_get_use_dhcp (NMDevice *dev); void nm_device_set_use_dhcp (NMDevice *dev, gboolean use_dhcp); +NMDHCP4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); gboolean nm_device_set_ip4_config (NMDevice *dev, diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 77c78f0bf..4831ab677 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * @@ -18,7 +18,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2005 Red Hat, Inc. + * (C) Copyright 2005 - 2008 Red Hat, Inc. */ @@ -57,7 +57,6 @@ typedef struct { GPtrArray *domains; GPtrArray *searches; - gchar *hostname; GSList *routes; } NMIP4ConfigPrivate; @@ -65,7 +64,6 @@ typedef struct { enum { PROP_0, PROP_ADDRESSES, - PROP_HOSTNAME, PROP_NAMESERVERS, PROP_DOMAINS, PROP_ROUTES, @@ -223,24 +221,6 @@ void nm_ip4_config_reset_nameservers (NMIP4Config *config) g_array_remove_range (priv->nameservers, 0, priv->nameservers->len); } -void nm_ip4_config_set_hostname (NMIP4Config *config, const char *hostname) -{ - g_return_if_fail (NM_IS_IP4_CONFIG (config)); - g_return_if_fail (hostname != NULL); - - if (!strlen (hostname)) - return; - - NM_IP4_CONFIG_GET_PRIVATE (config)->hostname = g_strdup (hostname); -} - -const char *nm_ip4_config_get_hostname (NMIP4Config *config) -{ - g_return_val_if_fail (NM_IS_IP4_CONFIG (config), NULL); - - return NM_IP4_CONFIG_GET_PRIVATE (config)->hostname; -} - void nm_ip4_config_take_route (NMIP4Config *config, NMSettingIP4Route *route) @@ -510,7 +490,6 @@ finalize (GObject *object) NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object); nm_utils_slist_free (priv->addresses, g_free); - g_free (priv->hostname); g_array_free (priv->nameservers, TRUE); g_ptr_array_free (priv->domains, TRUE); g_ptr_array_free (priv->searches, TRUE); @@ -527,9 +506,6 @@ get_property (GObject *object, guint prop_id, case PROP_ADDRESSES: nm_utils_ip4_addresses_to_gvalue (priv->addresses, value); break; - case PROP_HOSTNAME: - g_value_set_string (value, priv->hostname); - break; case PROP_NAMESERVERS: g_value_set_boxed (value, priv->nameservers); break; @@ -564,13 +540,6 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class) "IP4 addresses", DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_HOSTNAME, - g_param_spec_string (NM_IP4_CONFIG_HOSTNAME, - "Hostname", - "Hostname", - NULL, - G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_NAMESERVERS, g_param_spec_boxed (NM_IP4_CONFIG_NAMESERVERS, diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 92acb79e2..e2463b860 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -18,7 +18,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2004 Red Hat, Inc. + * (C) Copyright 2004 - 2008 Red Hat, Inc. */ #ifndef NM_IP4_CONFIG_H @@ -45,11 +45,8 @@ typedef struct { } NMIP4ConfigClass; #define NM_IP4_CONFIG_ADDRESSES "addresses" -#define NM_IP4_CONFIG_HOSTNAME "hostname" #define NM_IP4_CONFIG_NAMESERVERS "nameservers" #define NM_IP4_CONFIG_DOMAINS "domains" -#define NM_IP4_CONFIG_NIS_DOMAIN "nis-domain" -#define NM_IP4_CONFIG_NIS_SERVERS "nis-servers" #define NM_IP4_CONFIG_ROUTES "routes" GType nm_ip4_config_get_type (void); @@ -80,9 +77,6 @@ const NMSettingIP4Route * nm_ip4_config_get_route (NMIP4Config *config, guint32 guint32 nm_ip4_config_get_num_routes (NMIP4Config *config); void nm_ip4_config_reset_routes (NMIP4Config *config); -void nm_ip4_config_set_hostname (NMIP4Config *config, const char *hostname); -const char * nm_ip4_config_get_hostname (NMIP4Config *config); - void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain); const char * nm_ip4_config_get_domain (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_domains (NMIP4Config *config); diff --git a/src/nm-manager.c b/src/nm-manager.c index 62fbb0cf7..b7559027b 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -70,6 +70,10 @@ static void hal_manager_rfkill_changed_cb (NMHalManager *hal_mgr, static void hal_manager_hal_reappeared_cb (NMHalManager *hal_mgr, gpointer user_data); +static void system_settings_properties_changed_cb (DBusGProxy *proxy, + GHashTable *properties, + gpointer user_data); + #define SSD_POKE_INTERVAL 120000 typedef struct { @@ -95,6 +99,7 @@ typedef struct { DBusGProxy *system_proxy; DBusGProxy *system_props_proxy; GSList *unmanaged_udis; + char *hostname; PendingConnectionInfo *pending_connection_info; gboolean wireless_enabled; @@ -139,6 +144,9 @@ enum { PROP_WIRELESS_HARDWARE_ENABLED, PROP_ACTIVE_CONNECTIONS, + /* Not exported */ + PROP_HOSTNAME, + LAST_PROP }; @@ -280,6 +288,8 @@ nm_manager_init (NMManager *manager) priv->vpn_manager_id = id; g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); + + /* avahi-autoipd stuff */ priv->aipd_proxy = dbus_g_proxy_new_for_name (g_connection, NM_AUTOIP_DBUS_SERVICE, "/", @@ -300,7 +310,24 @@ nm_manager_init (NMManager *manager) manager, NULL); } else - nm_warning ("Could not initialize avahi-autoipd D-Bus proxy"); + nm_warning ("%s: could not initialize avahi-autoipd D-Bus proxy", __func__); + + /* System settings stuff */ + priv->system_props_proxy = dbus_g_proxy_new_for_name (g_connection, + NM_DBUS_SERVICE_SYSTEM_SETTINGS, + NM_DBUS_PATH_SETTINGS, + "org.freedesktop.NetworkManagerSettings.System"); + if (priv->system_props_proxy) { + dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->system_props_proxy, "PropertiesChanged", + DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->system_props_proxy, "PropertiesChanged", + G_CALLBACK (system_settings_properties_changed_cb), + manager, + NULL); + } else + nm_warning ("%s: could not initialize system settings properties D-Bus proxy", __func__); } NMState @@ -434,6 +461,8 @@ dispose (GObject *object) g_hash_table_destroy (priv->system_connections); priv->system_connections = NULL; + g_free (priv->hostname); + if (priv->system_props_proxy) { g_object_unref (priv->system_props_proxy); priv->system_props_proxy = NULL; @@ -526,6 +555,9 @@ get_property (GObject *object, guint prop_id, case PROP_ACTIVE_CONNECTIONS: g_value_take_boxed (value, get_active_connections (self, NULL)); break; + case PROP_HOSTNAME: + g_value_set_string (value, priv->hostname); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -579,6 +611,15 @@ nm_manager_class_init (NMManagerClass *manager_class) DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, G_PARAM_READABLE)); + /* Hostname is not exported over D-Bus */ + g_object_class_install_property + (object_class, PROP_HOSTNAME, + g_param_spec_string (NM_MANAGER_HOSTNAME, + "Hostname", + "Hostname", + NULL, + G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT)); + /* signals */ signals[DEVICE_ADDED] = g_signal_new ("device-added", @@ -1127,6 +1168,22 @@ handle_unmanaged_devices (NMManager *manager, GPtrArray *ops) g_slist_free (unmanaged); } +static void +handle_hostname (NMManager *manager, const char *hostname) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + + if (!hostname && !priv->hostname) + return; + + if (hostname && priv->hostname && !strcmp (hostname, priv->hostname)) + return; + + g_free (priv->hostname); + priv->hostname = (hostname && strlen (hostname)) ? g_strdup (hostname) : NULL; + g_object_notify (G_OBJECT (manager), NM_MANAGER_HOSTNAME); +} + static void system_settings_properties_changed_cb (DBusGProxy *proxy, GHashTable *properties, @@ -1136,10 +1193,12 @@ system_settings_properties_changed_cb (DBusGProxy *proxy, GValue *value; value = g_hash_table_lookup (properties, "UnmanagedDevices"); - if (!value || !G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) - return; + if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) + handle_unmanaged_devices (manager, g_value_get_boxed (value)); - handle_unmanaged_devices (manager, g_value_get_boxed (value)); + value = g_hash_table_lookup (properties, "Hostname"); + if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) + handle_hostname (manager, g_value_get_string (value)); } static void @@ -1158,6 +1217,7 @@ system_settings_get_unmanaged_devices_cb (DBusGProxy *proxy, "settings service: (%d) %s", __func__, error->code, error->message); g_error_free (error); + g_object_unref (proxy); return; } @@ -1165,37 +1225,45 @@ system_settings_get_unmanaged_devices_cb (DBusGProxy *proxy, handle_unmanaged_devices (manager, g_value_get_boxed (&value)); g_value_unset (&value); - g_object_unref (proxy); } static void -query_unmanaged_devices (NMManager *manager) +system_settings_get_hostname_cb (DBusGProxy *proxy, + DBusGProxyCall *call_id, + gpointer user_data) +{ + NMManager *manager = NM_MANAGER (user_data); + GError *error = NULL; + GValue value = { 0, }; + + if (!dbus_g_proxy_end_call (proxy, call_id, &error, + G_TYPE_VALUE, &value, + G_TYPE_INVALID)) { + nm_warning ("%s: Error getting hostname from the system settings service: (%d) %s", + __func__, error->code, error->message); + g_error_free (error); + g_object_unref (proxy); + return; + } + + if (G_VALUE_HOLDS (&value, G_TYPE_STRING)) + handle_hostname (manager, g_value_get_string (&value)); + + g_value_unset (&value); + g_object_unref (proxy); +} + +static void +query_system_settings_property (NMManager *manager, + const char *property, + DBusGProxyCallNotify callback) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *g_connection; DBusGProxy *get_proxy; g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - if (!priv->system_props_proxy) { - priv->system_props_proxy = dbus_g_proxy_new_for_name (g_connection, - NM_DBUS_SERVICE_SYSTEM_SETTINGS, - NM_DBUS_PATH_SETTINGS, - "org.freedesktop.NetworkManagerSettings.System"); - if (!priv->system_props_proxy) { - nm_warning ("Error: could not init system settings properties proxy."); - return; - } - - dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID); - dbus_g_proxy_add_signal (priv->system_props_proxy, "PropertiesChanged", - DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->system_props_proxy, "PropertiesChanged", - G_CALLBACK (system_settings_properties_changed_cb), - manager, - NULL); - } /* Get unmanaged devices */ get_proxy = dbus_g_proxy_new_for_name (g_connection, @@ -1203,12 +1271,9 @@ query_unmanaged_devices (NMManager *manager) NM_DBUS_PATH_SETTINGS, "org.freedesktop.DBus.Properties"); - dbus_g_proxy_begin_call (get_proxy, "Get", - system_settings_get_unmanaged_devices_cb, - manager, - NULL, - G_TYPE_STRING, "org.freedesktop.NetworkManagerSettings.System", - G_TYPE_STRING, "UnmanagedDevices", + dbus_g_proxy_begin_call (get_proxy, "Get", callback, manager, NULL, + G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS_SYSTEM, + G_TYPE_STRING, property, G_TYPE_INVALID); } @@ -1240,7 +1305,8 @@ nm_manager_name_owner_changed (NMDBusManager *mgr, } /* System Settings service appeared, update stuff */ - query_unmanaged_devices (manager); + query_system_settings_property (manager, "UnmanagedDevices", system_settings_get_unmanaged_devices_cb); + query_system_settings_property (manager, "Hostname", system_settings_get_hostname_cb); query_connections (manager, NM_CONNECTION_SCOPE_SYSTEM); } else { /* System Settings service disappeared, throw them away (?) */ @@ -1299,7 +1365,8 @@ initial_get_connections (gpointer user_data) if (nm_dbus_manager_name_has_owner (nm_dbus_manager_get (), NM_DBUS_SERVICE_SYSTEM_SETTINGS)) { - query_unmanaged_devices (manager); + query_system_settings_property (manager, "UnmanagedDevices", system_settings_get_unmanaged_devices_cb); + query_system_settings_property (manager, "Hostname", system_settings_get_hostname_cb); query_connections (manager, NM_CONNECTION_SCOPE_SYSTEM); } else { /* Try to activate the system settings daemon */ diff --git a/src/nm-manager.h b/src/nm-manager.h index fd744325f..ae6b9a4f5 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -19,6 +19,9 @@ #define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled" #define NM_MANAGER_ACTIVE_CONNECTIONS "active-connections" +/* Not exported */ +#define NM_MANAGER_HOSTNAME "hostname" + #define NM_MANAGER_CONNECTION_PROXY_TAG "dbus-proxy" #define NM_MANAGER_CONNECTION_SECRETS_PROXY_TAG "dbus-secrets-proxy" diff --git a/system-settings/plugins/ifcfg-fedora/plugin.c b/system-settings/plugins/ifcfg-fedora/plugin.c index dc6de9aa2..da3d95d28 100644 --- a/system-settings/plugins/ifcfg-fedora/plugin.c +++ b/system-settings/plugins/ifcfg-fedora/plugin.c @@ -1,5 +1,6 @@ /* NetworkManager system settings service * + * Dan Williams * Søren Sandmann * * This program is free software; you can redistribute it and/or modify @@ -44,6 +45,8 @@ #include "plugin.h" #include "nm-system-config-interface.h" #include "nm-ifcfg-connection.h" +#include "nm-inotify-helper.h" +#include "shvar.h" #define IFCFG_DIR SYSCONFDIR"/sysconfig/network-scripts/" @@ -74,6 +77,10 @@ typedef struct { GHashTable *connections; + gulong ih_event_id; + int sc_network_wd; + char *hostname; + GFileMonitor *monitor; guint monitor_id; } SCPluginIfcfgPrivate; @@ -417,7 +424,7 @@ dir_changed (GFileMonitor *monitor, } static void -setup_monitoring (SCPluginIfcfg *plugin) +setup_ifcfg_monitoring (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GFile *file; @@ -453,7 +460,7 @@ get_connections (NMSystemConfigInterface *config) GSList *list = NULL; if (!priv->connections) { - setup_monitoring (plugin); + setup_ifcfg_monitoring (plugin); read_connections (plugin); } @@ -462,6 +469,70 @@ get_connections (NMSystemConfigInterface *config) return list; } +#define SC_NETWORK_FILE SYSCONFDIR"/sysconfig/network" + +static char * +plugin_get_hostname (SCPluginIfcfg *plugin) +{ + shvarFile *network; + char *hostname; + + network = svNewFile (SC_NETWORK_FILE); + if (!network) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Could not get hostname: failed to read " SC_NETWORK_FILE); + return FALSE; + } + + hostname = svGetValue (network, "HOSTNAME"); + svCloseFile (network); + return hostname; +} + +static gboolean +plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname) +{ + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + shvarFile *network; + + network = svCreateFile (SC_NETWORK_FILE); + if (!network) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Could not save hostname: failed to create/open " SC_NETWORK_FILE); + return FALSE; + } + + svSetValue (network, "HOSTNAME", hostname); + svWriteFile (network, 0644); + svCloseFile (network); + + g_free (priv->hostname); + priv->hostname = hostname ? g_strdup (hostname) : NULL; + return TRUE; +} + +static void +sc_network_changed_cb (NMInotifyHelper *ih, + struct inotify_event *evt, + const char *path, + gpointer user_data) +{ + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + char *new_hostname; + + if (evt->wd != priv->sc_network_wd) + return; + + new_hostname = plugin_get_hostname (plugin); + if ( (new_hostname && !priv->hostname) + || (!new_hostname && priv->hostname) + || (priv->hostname && new_hostname && strcmp (priv->hostname, new_hostname))) { + g_free (priv->hostname); + priv->hostname = new_hostname; + g_object_notify (G_OBJECT (plugin), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); + } else + g_free (new_hostname); +} + static void init (NMSystemConfigInterface *config, NMSystemConfigHalManager *hal_manager) { @@ -476,6 +547,7 @@ sc_plugin_ifcfg_init (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GError *error = NULL; + NMInotifyHelper *ih; priv->g_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (!priv->g_connection) { @@ -483,6 +555,12 @@ sc_plugin_ifcfg_init (SCPluginIfcfg *plugin) error->message ? error->message : "(unknown)"); g_error_free (error); } + + ih = nm_inotify_helper_get (); + priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (sc_network_changed_cb), plugin); + priv->sc_network_wd = nm_inotify_helper_add_watch (ih, SC_NETWORK_FILE); + + priv->hostname = plugin_get_hostname (plugin); } static void @@ -490,9 +568,19 @@ dispose (GObject *object) { SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object); SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + NMInotifyHelper *ih; g_object_unref (priv->hal_mgr); + ih = nm_inotify_helper_get (); + + g_signal_handler_disconnect (ih, priv->ih_event_id); + + if (priv->sc_network_wd >= 0) + nm_inotify_helper_remove_watch (ih, priv->sc_network_wd); + + g_free (priv->hostname); + if (priv->g_connection) dbus_g_connection_unref (priv->g_connection); @@ -520,6 +608,8 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object); + switch (prop_id) { case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: g_value_set_string (value, IFCFG_PLUGIN_NAME); @@ -527,6 +617,32 @@ get_property (GObject *object, guint prop_id, case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: g_value_set_string (value, IFCFG_PLUGIN_INFO); break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); + break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: + g_value_set_string (value, priv->hostname); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + const char *hostname; + + switch (prop_id) { + case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: + hostname = g_value_get_string (value); + if (!strlen (hostname)) + hostname = NULL; + plugin_set_hostname (SC_PLUGIN_IFCFG (object), + (hostname && strlen (hostname)) ? hostname : NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -543,14 +659,23 @@ sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class) object_class->dispose = dispose; object_class->finalize = finalize; object_class->get_property = get_property; + object_class->set_property = set_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); + NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, + NM_SYSTEM_CONFIG_INTERFACE_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, + NM_SYSTEM_CONFIG_INTERFACE_INFO); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, + NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, + NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); } static void diff --git a/system-settings/plugins/ifcfg-fedora/shvar.c b/system-settings/plugins/ifcfg-fedora/shvar.c index 5ecae90fc..3faf31929 100644 --- a/system-settings/plugins/ifcfg-fedora/shvar.c +++ b/system-settings/plugins/ifcfg-fedora/shvar.c @@ -49,17 +49,15 @@ svOpenFile(const char *name, gboolean create) s = g_malloc0(sizeof(shvarFile)); -#if 1 /* NetworkManager local change */ - s->fd = open(name, O_RDONLY); /* NOT O_CREAT */ - if (s->fd != -1) closefd = 1; -#else - s->fd = open(name, O_RDWR); /* NOT O_CREAT */ - if (s->fd == -1) { + s->fd = -1; + if (create) + s->fd = open(name, O_RDWR); /* NOT O_CREAT */ + + if (!create || s->fd == -1) { /* try read-only */ s->fd = open(name, O_RDONLY); /* NOT O_CREAT */ if (s->fd != -1) closefd = 1; } -#endif s->fileName = g_strdup(name); if (s->fd != -1) { diff --git a/system-settings/plugins/ifcfg-suse/plugin.c b/system-settings/plugins/ifcfg-suse/plugin.c index 6bed65abb..e47f1dae7 100644 --- a/system-settings/plugins/ifcfg-suse/plugin.c +++ b/system-settings/plugins/ifcfg-suse/plugin.c @@ -379,6 +379,12 @@ get_property (GObject *object, guint prop_id, case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: g_value_set_string (value, IFCFG_PLUGIN_INFO); break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE); + break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: + g_value_set_string (value, ""); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -402,6 +408,14 @@ sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class) g_object_class_override_property (object_class, NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, NM_SYSTEM_CONFIG_INTERFACE_INFO); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, + NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, + NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); } static void diff --git a/system-settings/plugins/keyfile/plugin.c b/system-settings/plugins/keyfile/plugin.c index a930e0e3f..a54d76edf 100644 --- a/system-settings/plugins/keyfile/plugin.c +++ b/system-settings/plugins/keyfile/plugin.c @@ -283,6 +283,12 @@ get_property (GObject *object, guint prop_id, case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: g_value_set_string (value, KEYFILE_PLUGIN_INFO); break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS); + break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: + g_value_set_string (value, ""); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -324,12 +330,20 @@ sc_plugin_keyfile_class_init (SCPluginKeyfileClass *req_class) object_class->get_property = get_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); + NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, + NM_SYSTEM_CONFIG_INTERFACE_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, + NM_SYSTEM_CONFIG_INTERFACE_INFO); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, + NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, + NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); } static void diff --git a/system-settings/src/dbus-settings.c b/system-settings/src/dbus-settings.c index d7f31d62c..51d32328f 100644 --- a/system-settings/src/dbus-settings.c +++ b/system-settings/src/dbus-settings.c @@ -476,6 +476,27 @@ nm_sysconfig_settings_is_device_managed (NMSysconfigSettings *self, return TRUE; } +static NMSystemConfigInterface * +get_first_plugin_by_capability (NMSysconfigSettings *self, + guint32 capability) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + g_return_val_if_fail (self != NULL, NULL); + + /* Do any of the plugins support setting the hostname? */ + for (iter = priv->plugins; iter; iter = iter->next) { + NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; + + g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); + if (caps & capability) + return NM_SYSTEM_CONFIG_INTERFACE (iter->data); + } + + return NULL; +} + static gboolean impl_settings_add_connection (NMSysconfigSettings *self, GHashTable *hash, @@ -485,18 +506,10 @@ impl_settings_add_connection (NMSysconfigSettings *self, NMConnection *connection; GSList *iter; GError *err = NULL, *cnfh_error = NULL; - gboolean success; + gboolean success = FALSE; /* Do any of the plugins support adding? */ - success = FALSE; - for (iter = priv->plugins; iter && success == FALSE; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - success = (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS); - } - - if (!success) { + if (!get_first_plugin_by_capability (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) { err = g_error_new (NM_SYSCONFIG_SETTINGS_ERROR, NM_SYSCONFIG_SETTINGS_ERROR_ADD_NOT_SUPPORTED, "%s", "None of the registered plugins support add."); @@ -559,19 +572,12 @@ impl_settings_save_hostname (NMSysconfigSettings *self, DBusGMethodInvocation *context) { NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - gboolean success = FALSE; GError *err = NULL; GSList *iter; + gboolean success = FALSE; /* Do any of the plugins support setting the hostname? */ - for (iter = priv->plugins; iter && success == FALSE; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - success = (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); - } - - if (!success) { + if (!get_first_plugin_by_capability (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { err = g_error_new (NM_SYSCONFIG_SETTINGS_ERROR, NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "%s", "None of the registered plugins support setting the hostname."); @@ -581,8 +587,8 @@ impl_settings_save_hostname (NMSysconfigSettings *self, if (!check_polkit_privileges (priv->g_connection, priv->pol_ctx, context, &err)) goto out; - /* Now actually set the hostname in all plugins */ - for (iter = priv->plugins, success = FALSE; iter; iter = iter->next) { + /* Set the hostname in all plugins */ + for (iter = priv->plugins; iter; iter = iter->next) { NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); diff --git a/system-settings/src/dbus-settings.h b/system-settings/src/dbus-settings.h index d51044b09..d2256c0b7 100644 --- a/system-settings/src/dbus-settings.h +++ b/system-settings/src/dbus-settings.h @@ -39,6 +39,7 @@ typedef struct _NMSysconfigSettingsClass NMSysconfigSettingsClass; #define NM_SYSCONFIG_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsClass)) #define NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES "unmanaged-devices" +#define NM_SYSCONFIG_SETTINGS_HOSTNAME "hostname" struct _NMSysconfigSettings { diff --git a/system-settings/src/nm-system-config-error.c b/system-settings/src/nm-system-config-error.c index e60e52528..6dd1173c7 100644 --- a/system-settings/src/nm-system-config-error.c +++ b/system-settings/src/nm-system-config-error.c @@ -29,6 +29,8 @@ nm_sysconfig_settings_error_get_type (void) ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, "UpdateNotSupported"), ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, "DeleteNotSupported"), ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_ADD_FAILED, "AddFailed"), + ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, "SaveHostnameNotSupported"), + ENUM_ENTRY (NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, "SaveHostnameFailed"), { 0, 0, 0 } }; diff --git a/system-settings/src/nm-system-config-error.h b/system-settings/src/nm-system-config-error.h index 186631de7..5211cd620 100644 --- a/system-settings/src/nm-system-config-error.h +++ b/system-settings/src/nm-system-config-error.h @@ -13,7 +13,9 @@ enum { NM_SYSCONFIG_SETTINGS_ERROR_ADD_NOT_SUPPORTED, NM_SYSCONFIG_SETTINGS_ERROR_UPDATE_NOT_SUPPORTED, NM_SYSCONFIG_SETTINGS_ERROR_DELETE_NOT_SUPPORTED, - NM_SYSCONFIG_SETTINGS_ERROR_ADD_FAILED + NM_SYSCONFIG_SETTINGS_ERROR_ADD_FAILED, + NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED, + NM_SYSCONFIG_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED, }; #define NM_SYSCONFIG_SETTINGS_ERROR (nm_sysconfig_settings_error_quark ()) diff --git a/system-settings/src/nm-system-config-interface.c b/system-settings/src/nm-system-config-interface.c index 3b7373060..8e8c307c5 100644 --- a/system-settings/src/nm-system-config-interface.c +++ b/system-settings/src/nm-system-config-interface.c @@ -17,7 +17,7 @@ * 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 Red Hat, Inc. + * (C) Copyright 2007 - 2008 Red Hat, Inc. */ #include "nm-system-config-interface.h" @@ -48,6 +48,24 @@ interface_init (gpointer g_iface) NULL, G_PARAM_READABLE)); + g_object_interface_install_property + (g_iface, + g_param_spec_uint (NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, + "Capabilities", + "Plugin capabilties", + NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, + NM_SYSTEM_CONFIG_INTERFACE_CAP_LAST - 1, + NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, + G_PARAM_READABLE)); + + g_object_interface_install_property + (g_iface, + g_param_spec_string (NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, + "Hostname", + "Configured hostname", + NULL, + G_PARAM_READWRITE)); + /* Signals */ g_signal_new ("connection-added", iface_type, @@ -129,14 +147,6 @@ nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *confi return NULL; } -gboolean -nm_system_config_interface_supports_add (NMSystemConfigInterface *config) -{ - g_return_val_if_fail (config != NULL, FALSE); - - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection != NULL; -} - gboolean nm_system_config_interface_add_connection (NMSystemConfigInterface *config, NMConnection *connection, diff --git a/system-settings/src/nm-system-config-interface.h b/system-settings/src/nm-system-config-interface.h index 4a258e3e9..a43e67430 100644 --- a/system-settings/src/nm-system-config-interface.h +++ b/system-settings/src/nm-system-config-interface.h @@ -60,13 +60,23 @@ GObject * nm_system_config_factory (void); #define NM_SYSTEM_CONFIG_INTERFACE_NAME "name" #define NM_SYSTEM_CONFIG_INTERFACE_INFO "info" +#define NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES "capabilities" #define NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME "hostname" +typedef enum { + NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE = 0x00000000, + NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS = 0x00000001, + NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME = 0x00000002, + + NM_SYSTEM_CONFIG_INTERFACE_CAP_LAST = NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME +} NMSystemConfigInterfaceCapabilities; + typedef enum { NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST = 0x1000, NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME = NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST, NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, + NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, } NMSystemConfigInterfaceProp; @@ -110,12 +120,10 @@ GType nm_system_config_interface_get_type (void); void nm_system_config_interface_init (NMSystemConfigInterface *config, NMSystemConfigHalManager *hal_manager); -GSList * nm_system_config_interface_get_connections (NMSystemConfigInterface *config); +GSList *nm_system_config_interface_get_connections (NMSystemConfigInterface *config); GSList *nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *config); -gboolean nm_system_config_interface_supports_add (NMSystemConfigInterface *config); - gboolean nm_system_config_interface_add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error);