static GSList * get_unhandled_specs (NMSystemConfigInterface *config, const char *property) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); GSList *list = NULL, *list_iter; GHashTableIter iter; gpointer connection; char *spec; gboolean found; g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, &connection)) { g_object_get (connection, property, &spec, NULL); if (spec) { /* Ignore duplicates */ for (list_iter = list, found = FALSE; list_iter; list_iter = g_slist_next (list_iter)) { if (g_str_equal (list_iter->data, spec)) { found = TRUE; break; } } if (found) g_free (spec); else list = g_slist_prepend (list, spec); } } return list; }
static void remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); gboolean unmanaged, unrecognized; g_return_if_fail (self != NULL); g_return_if_fail (connection != NULL); _LOGI ("remove "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection)); unmanaged = !!nm_ifcfg_connection_get_unmanaged_spec (connection); unrecognized = !!nm_ifcfg_connection_get_unrecognized_spec (connection); g_object_ref (connection); g_hash_table_remove (priv->connections, nm_connection_get_uuid (NM_CONNECTION (connection))); nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); g_object_unref (connection); /* Emit changes _after_ removing the connection */ if (unmanaged) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); if (unrecognized) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED); }
static GSList * get_connections (NMSystemConfigInterface *config) { SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GSList *list = NULL; GHashTableIter iter; NMIfcfgConnection *connection; if (!priv->initialized) { if (nm_config_get_monitor_connection_files (nm_config_get ())) setup_ifcfg_monitoring (plugin); read_connections (plugin); priv->initialized = TRUE; } g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) { if ( !nm_ifcfg_connection_get_unmanaged_spec (connection) && !nm_ifcfg_connection_get_unrecognized_spec (connection)) list = g_slist_prepend (list, connection); } return list; }
static void init (NMSystemConfigInterface *config) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); priv->hostname_monitor = monitor_file_changes (HOSTNAME_FILE, hostname_changed, config); priv->dhcp_monitor = monitor_file_changes (CONF_DHCP, hostname_changed, config); if (!hostname_is_dynamic ()) priv->hostname = hostname_read (); }
static void hostname_changed (gpointer data) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (data); g_free (priv->hostname); if (hostname_is_dynamic ()) priv->hostname = NULL; else priv->hostname = hostname_read (); g_object_notify (G_OBJECT (data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); }
static NMIfcfgConnection * _internal_new_connection (SCPluginIfcfg *self, const char *path, NMConnection *source, GError **error) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); NMIfcfgConnection *connection; const char *cid; GError *local = NULL; gboolean ignore_error = FALSE; if (!source) { PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", path); } connection = nm_ifcfg_connection_new (path, source, &local, &ignore_error); if (!connection) { if (!ignore_error) { PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " error: %s", (local && local->message) ? local->message : "(unknown)"); } g_propagate_error (error, local); return NULL; } cid = nm_connection_get_id (NM_CONNECTION (connection)); g_assert (cid); g_hash_table_insert (priv->connections, (gpointer) nm_ifcfg_connection_get_path (connection), connection); PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " read connection '%s'", cid); if (nm_ifcfg_connection_get_unmanaged_spec (connection)) { PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " "device due to NM_CONTROLLED/BRIDGE/VLAN.", cid); } else { /* Wait for the connection to become unmanaged once it knows the * hardware IDs of its device, if/when the device gets plugged in. */ g_signal_connect (G_OBJECT (connection), "notify::" NM_IFCFG_CONNECTION_UNMANAGED, G_CALLBACK (connection_unmanaged_changed), self); } /* watch changes of ifcfg hardlinks */ g_signal_connect (G_OBJECT (connection), "ifcfg-changed", G_CALLBACK (connection_ifcfg_changed), self); return connection; }
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); if (evt->wd != priv->sc_network_wd) return; hostname_maybe_changed (plugin); }
static void dispose (GObject *object) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object); if (priv->dhcp_monitor) g_object_unref (priv->dhcp_monitor); if (priv->hostname_monitor) g_object_unref (priv->hostname_monitor); g_free (priv->hostname); G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object); }
static NMIfcfgConnection * find_by_path (SCPluginIfcfg *self, const char *path) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); GHashTableIter iter; NMSettingsConnection *candidate = NULL; g_return_val_if_fail (path != NULL, NULL); g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) { if (g_strcmp0 (path, nm_settings_connection_get_filename (candidate)) == 0) return NM_IFCFG_CONNECTION (candidate); } return NULL; }
static void dispose (GObject *object) { SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object); SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); NMInotifyHelper *ih; if (priv->bus) { dbus_g_connection_unref (priv->bus); priv->bus = NULL; } if (priv->ih_event_id) { ih = nm_inotify_helper_get (); g_signal_handler_disconnect (ih, priv->ih_event_id); priv->ih_event_id = 0; if (priv->sc_network_wd >= 0) nm_inotify_helper_remove_watch (ih, priv->sc_network_wd); } 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_object_unref (priv->hostname_monitor); } g_free (priv->hostname); if (priv->connections) { g_hash_table_destroy (priv->connections); priv->connections = NULL; } if (priv->ifcfg_monitor) { if (priv->ifcfg_monitor_id) g_signal_handler_disconnect (priv->ifcfg_monitor, priv->ifcfg_monitor_id); g_file_monitor_cancel (priv->ifcfg_monitor); g_object_unref (priv->ifcfg_monitor); } G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object); }
static void plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GIOChannel *channel; channel = g_io_channel_new_file (HOSTNAME_FILE, "w", NULL); if (channel) { g_io_channel_write_chars (channel, hostname, -1, NULL, NULL); g_io_channel_write_chars (channel, "\n", -1, NULL, NULL); g_io_channel_shutdown (channel, TRUE, NULL); g_io_channel_unref (channel); } g_free (priv->hostname); priv->hostname = g_strdup (hostname); }
static void setup_ifcfg_monitoring (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GFile *file; GFileMonitor *monitor; file = g_file_new_for_path (IFCFG_DIR "/"); monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); if (monitor) { priv->ifcfg_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (ifcfg_dir_changed), plugin); priv->ifcfg_monitor = monitor; } }
G_MODULE_EXPORT GObject * nm_system_config_factory (void) { static SCPluginIfcfg *singleton = NULL; SCPluginIfcfgPrivate *priv; if (!singleton) { singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL)); priv = SC_PLUGIN_IFCFG_GET_PRIVATE (singleton); if (priv->bus) dbus_g_connection_register_g_object (priv->bus, DBUS_OBJECT_PATH, G_OBJECT (singleton)); _LOGD ("Acquired D-Bus service %s", DBUS_SERVICE_NAME); } else g_object_ref (singleton); return G_OBJECT (singleton); }
static void connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data) { SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data); SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); const char *path; path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection)); g_return_if_fail (path != NULL); if (!priv->ifcfg_monitor) { _LOGD ("connection_ifcfg_changed("NM_IFCFG_CONNECTION_LOG_FMTD"): %s", NM_IFCFG_CONNECTION_LOG_ARGD (connection), "ignore event"); return; } _LOGD ("connection_ifcfg_changed("NM_IFCFG_CONNECTION_LOG_FMTD"): %s", NM_IFCFG_CONNECTION_LOG_ARGD (connection), "reload"); update_connection (self, NULL, path, connection, TRUE, NULL, NULL); }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: g_value_set_string (value, IFCFG_PLUGIN_NAME); break; 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, SC_PLUGIN_IFCFG_GET_PRIVATE (object)->hostname); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); gboolean managed = FALSE; const char *path; g_return_if_fail (self != NULL); g_return_if_fail (connection != NULL); managed = !nm_ifcfg_connection_get_unmanaged_spec (connection); path = nm_ifcfg_connection_get_path (connection); g_object_ref (connection); g_hash_table_remove (priv->connections, path); nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); g_object_unref (connection); /* Emit unmanaged changes _after_ removing the connection */ if (managed == FALSE) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); }
static void sc_plugin_ifcfg_init (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); NMInotifyHelper *ih; GError *error = NULL; gboolean success = FALSE; GFile *file; GFileMonitor *monitor; priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* We watch SC_NETWORK_FILE via NMInotifyHelper (which doesn't track file creation but * *does* track modifications made via other hard links), since we expect it to always * exist. But we watch HOSTNAME_FILE via GFileMonitor (which has the opposite * semantics), since /etc/hostname might not exist, but is unlikely to have hard * links. bgo 532815 is the bug for being able to just use GFileMonitor for both. */ 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); file = g_file_new_for_path (HOSTNAME_FILE); monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); if (monitor) { priv->hostname_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (hostname_changed_cb), plugin); priv->hostname_monitor = monitor; } priv->hostname = plugin_get_hostname (plugin); priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (!priv->bus) { _LOGW ("Couldn't connect to D-Bus: %s", error->message); g_clear_error (&error); } else { DBusConnection *tmp; DBusGProxy *proxy; int result; tmp = dbus_g_connection_get_connection (priv->bus); dbus_connection_set_exit_on_disconnect (tmp, FALSE); proxy = dbus_g_proxy_new_for_name (priv->bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"); if (!dbus_g_proxy_call (proxy, "RequestName", &error, G_TYPE_STRING, DBUS_SERVICE_NAME, G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID)) { _LOGW ("Couldn't acquire D-Bus service: %s", error->message); g_clear_error (&error); } else if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { _LOGW ("Couldn't acquire ifcfgrh1 D-Bus service (already taken)"); } else success = TRUE; } if (!success) { if (priv->bus) { dbus_g_connection_unref (priv->bus); priv->bus = NULL; } } }
static gboolean plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); shvarFile *network; char *hostname_eol; gboolean ret; #if HAVE_SELINUX security_context_t se_ctx_prev = NULL, se_ctx = NULL; struct stat file_stat = { .st_mode = 0 }; mode_t st_mode = 0; /* Get default context for HOSTNAME_FILE and set it for fscreate */ if (stat (HOSTNAME_FILE, &file_stat) == 0) st_mode = file_stat.st_mode; matchpathcon (HOSTNAME_FILE, st_mode, &se_ctx); matchpathcon_fini (); getfscreatecon (&se_ctx_prev); setfscreatecon (se_ctx); #endif hostname_eol = g_strdup_printf ("%s\n", hostname); ret = g_file_set_contents (HOSTNAME_FILE, hostname_eol, -1, NULL); #if HAVE_SELINUX /* Restore previous context and cleanup */ setfscreatecon (se_ctx_prev); freecon (se_ctx); freecon (se_ctx_prev); #endif if (!ret) { _LOGW ("Could not save hostname: failed to create/open " HOSTNAME_FILE); g_free (hostname_eol); return FALSE; } g_free (priv->hostname); priv->hostname = g_strdup (hostname); g_free (hostname_eol); /* Remove "HOSTNAME" from SC_NETWORK_FILE, if present */ network = svOpenFile (SC_NETWORK_FILE, NULL); if (network) { svSetValue (network, "HOSTNAME", NULL, FALSE); svWriteFile (network, 0644, NULL); svCloseFile (network); } return TRUE; } static void hostname_maybe_changed (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); char *new_hostname; 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 connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) { g_hash_table_remove (SC_PLUGIN_IFCFG_GET_PRIVATE (user_data)->connections, nm_connection_get_uuid (NM_CONNECTION (obj))); }
static void read_connections (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GDir *dir; GError *err = NULL; const char *item; GHashTable *alive_connections; GHashTableIter iter; NMIfcfgConnection *connection; GPtrArray *dead_connections = NULL; guint i; GPtrArray *filenames; GHashTable *paths; dir = g_dir_open (IFCFG_DIR, 0, &err); if (!dir) { _LOGW ("Could not read directory '%s': %s", IFCFG_DIR, err->message); g_error_free (err); return; } alive_connections = g_hash_table_new (NULL, NULL); filenames = g_ptr_array_new_with_free_func (g_free); while ((item = g_dir_read_name (dir))) { char *full_path; if (utils_should_ignore_file (item, TRUE)) continue; if (utils_is_ifcfg_alias_file (item, NULL)) continue; full_path = g_build_filename (IFCFG_DIR, item, NULL); if (!utils_get_ifcfg_name (full_path, TRUE)) g_free (full_path); else g_ptr_array_add (filenames, full_path); } g_dir_close (dir); /* While reloading, we don't replace connections that we already loaded while * iterating over the files. * * To have sensible, reproducible behavior, sort the paths by last modification * time prefering older files. */ paths = _paths_from_connections (priv->connections); g_ptr_array_sort_with_data (filenames, (GCompareDataFunc) _sort_paths, paths); g_hash_table_destroy (paths); for (i = 0; i < filenames->len; i++) { connection = update_connection (plugin, NULL, filenames->pdata[i], NULL, FALSE, alive_connections, NULL); if (connection) g_hash_table_add (alive_connections, connection); } g_ptr_array_free (filenames, TRUE); g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) { if ( !g_hash_table_contains (alive_connections, connection) && nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection))) { if (!dead_connections) dead_connections = g_ptr_array_new (); g_ptr_array_add (dead_connections, connection); } } g_hash_table_destroy (alive_connections); if (dead_connections) { for (i = 0; i < dead_connections->len; i++) remove_connection (plugin, dead_connections->pdata[i]); g_ptr_array_free (dead_connections, TRUE); } }
static NMIfcfgConnection * update_connection (SCPluginIfcfg *self, NMConnection *source, const char *full_path, NMIfcfgConnection *connection, gboolean protect_existing_connection, GHashTable *protected_connections, GError **error) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); NMIfcfgConnection *connection_new; NMIfcfgConnection *connection_by_uuid; GError *local = NULL; const char *new_unmanaged = NULL, *old_unmanaged = NULL; const char *new_unrecognized = NULL, *old_unrecognized = NULL; gboolean unmanaged_changed = FALSE, unrecognized_changed = FALSE; const char *uuid; g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL); g_return_val_if_fail (full_path || source, NULL); if (full_path) _LOGD ("loading from file \"%s\"...", full_path); /* Create a NMIfcfgConnection instance, either by reading from @full_path or * based on @source. */ connection_new = nm_ifcfg_connection_new (source, full_path, error); if (!connection_new) { /* Unexpected failure. Probably the file is invalid? */ if ( connection && !protect_existing_connection && (!protected_connections || !g_hash_table_contains (protected_connections, connection))) remove_connection (self, connection); return NULL; } uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new)); connection_by_uuid = g_hash_table_lookup (priv->connections, uuid); if ( connection && connection != connection_by_uuid) { if ( (protect_existing_connection && connection_by_uuid != NULL) || (protected_connections && g_hash_table_contains (protected_connections, connection))) { NMIfcfgConnection *conflicting = (protect_existing_connection && connection_by_uuid != NULL) ? connection_by_uuid : connection; if (source) _LOGW ("cannot update protected connection "NM_IFCFG_CONNECTION_LOG_FMT" due to conflicting UUID %s", NM_IFCFG_CONNECTION_LOG_ARG (conflicting), uuid); else _LOGW ("cannot load %s due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, full_path, NM_IFCFG_CONNECTION_LOG_ARG (conflicting)); g_object_unref (connection_new); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Cannot update protected connection due to conflicting UUID"); return NULL; } /* The new connection has a different UUID then the original one that we * are about to update. Remove @connection. */ remove_connection (self, connection); } /* Check if the found connection with the same UUID is not protected from updating. */ if ( connection_by_uuid && ( (!connection && protect_existing_connection) || (protected_connections && g_hash_table_contains (protected_connections, connection_by_uuid)))) { if (source) _LOGW ("cannot update connection due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_by_uuid)); else _LOGW ("cannot load %s due to conflicting UUID for "NM_IFCFG_CONNECTION_LOG_FMT, full_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_by_uuid)); g_object_unref (connection_new); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Skip updating protected connection during reload"); return NULL; } /* Evaluate unmanaged/unrecognized flags. */ if (connection_by_uuid) old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection_by_uuid); new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection_new); unmanaged_changed = g_strcmp0 (old_unmanaged, new_unmanaged); if (connection_by_uuid) old_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (connection_by_uuid); new_unrecognized = nm_ifcfg_connection_get_unrecognized_spec (connection_new); unrecognized_changed = g_strcmp0 (old_unrecognized, new_unrecognized); if (connection_by_uuid) { const char *old_path; old_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)); if ( !unmanaged_changed && !unrecognized_changed && nm_connection_compare (NM_CONNECTION (connection_by_uuid), NM_CONNECTION (connection_new), NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { if (old_path && g_strcmp0 (old_path, full_path) != 0) _LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT" without other changes", nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)), NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); } else { /******************************************************* * UPDATE *******************************************************/ if (source) _LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT" from %s", NM_IFCFG_CONNECTION_LOG_ARG (connection_new), NM_IFCFG_CONNECTION_LOG_PATH (old_path)); else if (!g_strcmp0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new)))) _LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); else if (old_path) _LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT, old_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); else _LOGI ("update and persist "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); g_object_set (connection_by_uuid, NM_IFCFG_CONNECTION_UNMANAGED_SPEC, new_unmanaged, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized, NULL); if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid), NM_CONNECTION (connection_new), FALSE, /* don't set Unsaved */ "ifcfg-update", &local)) { /* Shouldn't ever get here as 'connection_new' was verified by the reader already * and the UUID did not change. */ g_assert_not_reached (); } g_assert_no_error (local); if (new_unmanaged || new_unrecognized) { if (!old_unmanaged && !old_unrecognized) { g_object_ref (connection_by_uuid); /* Unexport the connection by telling the settings service it's * been removed. */ nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection_by_uuid)); /* Remove the path so that claim_connection() doesn't complain later when * interface gets managed and connection is re-added. */ nm_connection_set_path (NM_CONNECTION (connection_by_uuid), NULL); /* signal_remove() will end up removing the connection from our hash, * so add it back now. */ g_hash_table_insert (priv->connections, g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))), connection_by_uuid); } } else { if (old_unmanaged /* && !new_unmanaged */) { _LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" and its device because NM_CONTROLLED was true.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid); } else if (old_unrecognized /* && !new_unrecognized */) { _LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" because it is now a recognized type.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid); } } if (unmanaged_changed) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); if (unrecognized_changed) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED); } nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path); g_object_unref (connection_new); return connection_by_uuid; } else { /******************************************************* * ADD *******************************************************/ if (source) _LOGI ("add connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); else _LOGI ("new connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new); g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed_cb), self); if (nm_ifcfg_connection_get_unmanaged_spec (connection_new)) { const char *spec; const char *device_id; spec = nm_ifcfg_connection_get_unmanaged_spec (connection_new); device_id = strchr (spec, ':'); if (device_id) device_id++; else device_id = spec; _LOGW ("Ignoring connection "NM_IFCFG_CONNECTION_LOG_FMT" / device '%s' due to NM_CONTROLLED=no.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new), device_id); } else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new)) _LOGW ("Ignoring connection "NM_IFCFG_CONNECTION_LOG_FMT" of unrecognized type.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); /* watch changes of ifcfg hardlinks */ g_signal_connect (G_OBJECT (connection_new), "ifcfg-changed", G_CALLBACK (connection_ifcfg_changed), self); if (!source) { /* Only raise the signal if we were called without source, i.e. if we read the connection from file. * Otherwise, we were called by add_connection() which does not expect the signal. */ if (nm_ifcfg_connection_get_unmanaged_spec (connection_new)) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new)) g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED); else g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new); } return connection_new; } }