diff options
Diffstat (limited to 'src/NetworkManagerUtils.c')
| -rw-r--r-- | src/NetworkManagerUtils.c | 257 |
1 files changed, 159 insertions, 98 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 89bd357f..a3bd6013 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -23,6 +23,8 @@ #include "NetworkManagerUtils.h" +#include "nm-utils/nm-c-list.h" + #include "nm-common-macros.h" #include "nm-utils.h" #include "nm-setting-connection.h" @@ -31,7 +33,6 @@ #include "nm-core-internal.h" #include "platform/nm-platform.h" -#include "nm-exported-object.h" #include "nm-auth-utils.h" /*****************************************************************************/ @@ -68,98 +69,93 @@ nm_utils_get_shared_wifi_permission (NMConnection *connection) /*****************************************************************************/ static char * -get_new_connection_name (const GSList *existing, +get_new_connection_name (NMConnection *const*existing_connections, const char *preferred, const char *fallback_prefix) { - GSList *names = NULL; - const GSList *iter; - char *cname = NULL; - int i = 0; - gboolean preferred_found = FALSE; + gs_free const char **existing_names = NULL; + guint i, existing_len = 0; g_assert (fallback_prefix); - for (iter = existing; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = NM_CONNECTION (iter->data); - const char *id; + if (existing_connections) { + existing_len = NM_PTRARRAY_LEN (existing_connections); + existing_names = g_new (const char *, existing_len); + for (i = 0; i < existing_len; i++) { + NMConnection *candidate; + const char *id; + + candidate = existing_connections[i]; + nm_assert (NM_IS_CONNECTION (candidate)); + + id = nm_connection_get_id (candidate); + nm_assert (id); - id = nm_connection_get_id (candidate); - g_assert (id); - names = g_slist_append (names, (gpointer) id); + existing_names[i] = id; - if (preferred && !preferred_found && (strcmp (preferred, id) == 0)) - preferred_found = TRUE; + if ( preferred + && nm_streq (preferred, id)) { + /* the preferred name is already taken. Forget about it. */ + preferred = NULL; + } + } + nm_assert (!existing_connections[i]); } /* Return the preferred name if it was unique */ - if (preferred && !preferred_found) { - g_slist_free (names); + if (preferred) return g_strdup (preferred); - } /* Otherwise find the next available unique connection name using the given * connection name template. */ - while (!cname && (i++ < 10000)) { + for (i = 1; TRUE; i++) { char *temp; - gboolean found = FALSE; - /* Translators: the first %s is a prefix for the connection id, such + /* TRANSLATORS: the first %s is a prefix for the connection id, such * as "Wired Connection" or "VPN Connection". The %d is a number * that is combined with the first argument to create a unique * connection id. */ - temp = g_strdup_printf (C_("connection id fallback", "%s %d"), + temp = g_strdup_printf (C_("connection id fallback", "%s %u"), fallback_prefix, i); - for (iter = names; iter; iter = g_slist_next (iter)) { - if (!strcmp (iter->data, temp)) { - found = TRUE; - break; - } - } - if (!found) - cname = temp; - else - g_free (temp); - } - g_slist_free (names); - return cname; + if (nm_utils_strv_find_first ((char **) existing_names, + existing_len, + temp) < 0) + return temp; + + g_free (temp); + } } static char * get_new_connection_ifname (NMPlatform *platform, - const GSList *existing, + NMConnection *const*existing_connections, const char *prefix) { - int i; - char *name; - const GSList *iter; - gboolean found; + guint i, j; + + for (i = 0; TRUE; i++) { + char *name; - for (i = 0; i < 500; i++) { name = g_strdup_printf ("%s%d", prefix, i); if (nm_platform_link_get_by_ifname (platform, name)) goto next; - for (iter = existing, found = FALSE; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = iter->data; - - if (g_strcmp0 (nm_connection_get_interface_name (candidate), name) == 0) { - found = TRUE; - break; + if (existing_connections) { + for (j = 0; existing_connections[j]; j++) { + if (nm_streq0 (nm_connection_get_interface_name (existing_connections[j]), + name)) + goto next; } } - if (!found) - return name; + return name; - next: +next: g_free (name); } - - return NULL; } const char * @@ -251,7 +247,7 @@ void nm_utils_complete_generic (NMPlatform *platform, NMConnection *connection, const char *ctype, - const GSList *existing, + NMConnection *const*existing_connections, const char *preferred_id, const char *fallback_id_prefix, const char *ifname_prefix, @@ -278,14 +274,14 @@ nm_utils_complete_generic (NMPlatform *platform, /* Add a connection ID if absent */ if (!nm_setting_connection_get_id (s_con)) { - id = get_new_connection_name (existing, preferred_id, fallback_id_prefix); + id = get_new_connection_name (existing_connections, preferred_id, fallback_id_prefix); g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_ID, id, NULL); g_free (id); } /* Add an interface name, if requested */ if (ifname_prefix && !nm_setting_connection_get_interface_name (s_con)) { - ifname = get_new_connection_ifname (platform, existing, ifname_prefix); + ifname = get_new_connection_ifname (platform, existing_connections, ifname_prefix); g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL); g_free (ifname); } @@ -880,58 +876,123 @@ nm_utils_match_connection (NMConnection *const*connections, /*****************************************************************************/ -/** - * nm_utils_g_value_set_object_path: - * @value: a #GValue, initialized to store an object path - * @object: (allow-none): an #NMExportedObject - * - * Sets @value to @object's object path. If @object is %NULL, or not - * exported, @value is set to "/". - */ -void -nm_utils_g_value_set_object_path (GValue *value, gpointer object) +int +nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, + const char *match_device_type, + const GSList *specs, + int no_match_value) { - g_return_if_fail (!object || NM_IS_EXPORTED_OBJECT (object)); + NMMatchSpecMatchType m; + + /* we can only match by certain properties that are available on the + * platform link (and even @pllink might be missing. + * + * It's still useful because of specs like "*" and "except:interface-name:eth0", + * which match even in that case. */ + m = nm_match_spec_device (specs, + pllink ? pllink->name : NULL, + match_device_type, + pllink ? pllink->driver : NULL, + NULL, + NULL, + NULL); + + switch (m) { + case NM_MATCH_SPEC_MATCH: + return TRUE; + case NM_MATCH_SPEC_NEG_MATCH: + return FALSE; + case NM_MATCH_SPEC_NO_MATCH: + return no_match_value; + } + nm_assert_not_reached (); + return no_match_value; +} - if (object && nm_exported_object_is_exported (object)) - g_value_set_string (value, nm_exported_object_get_path (object)); - else - g_value_set_string (value, "/"); +/*****************************************************************************/ + +struct _NMShutdownWaitObjHandle { + CList lst; + GObject *watched_obj; + const char *msg_reason; +}; + +static CList _shutdown_waitobj_lst_head; + +static void +_shutdown_waitobj_unregister (NMShutdownWaitObjHandle *handle) +{ + c_list_unlink_stale (&handle->lst); + g_slice_free (NMShutdownWaitObjHandle, handle); + + /* FIXME(shutdown): check whether the object list is empty, and + * signal shutdown-complete */ +} + +static void +_shutdown_waitobj_cb (gpointer user_data, + GObject *where_the_object_was) +{ + NMShutdownWaitObjHandle *handle = user_data; + + nm_assert (handle); + nm_assert (handle->watched_obj == where_the_object_was); + _shutdown_waitobj_unregister (handle); } /** - * nm_utils_g_value_set_object_path_array: - * @value: a #GValue, initialized to store an object path - * @objects: a #GSList of #NMExportedObjects - * @filter_func: (allow-none): function to call on each object in @objects - * @user_data: data to pass to @filter_func + * _nm_shutdown_wait_obj_register: + * @watched_obj: the object to watch. Takes a weak reference on the object + * to be notified when it gets destroyed. + * @msg_reason: a reason message, for debugging and logging purposes. It + * must be a static string. Or at least, be alive at least as long as + * @watched_obj. So, theoretically, if you need a dynamic @msg_reason, + * you could attach it to @watched_obj's user-data. + * + * Keep track of @watched_obj until it gets destroyed. During shutdown, + * we wait until all watched objects are destroyed. This is useful, if + * this object still conducts some asynchronous action, which needs to + * complete before NetworkManager is allowed to terminate. We re-use + * the reference-counter of @watched_obj as signal, that the object + * is still used. + * + * FIXME(shutdown): proper shutdown is not yet implemented, and registering + * an object (currently) has no effect. * - * Sets @value to an array of object paths of the objects in @objects. + * Returns: a handle to unregister the object. The caller may choose to ignore + * the handle, in which case, the object will be automatically unregistered, + * once it gets destroyed. */ +NMShutdownWaitObjHandle * +_nm_shutdown_wait_obj_register (GObject *watched_obj, + const char *msg_reason) +{ + NMShutdownWaitObjHandle *handle; + + g_return_val_if_fail (G_IS_OBJECT (watched_obj), NULL); + + if (G_UNLIKELY (!_shutdown_waitobj_lst_head.next)) + c_list_init (&_shutdown_waitobj_lst_head); + + handle = g_slice_new (NMShutdownWaitObjHandle); + handle->watched_obj = watched_obj; + /* we don't clone the string. We require the caller to use pass a static message. + * If he really cannot do that, he should attach the string to the watched_obj + * as user-data. */ + handle->msg_reason = msg_reason; + c_list_link_tail (&_shutdown_waitobj_lst_head, &handle->lst); + g_object_weak_ref (watched_obj, _shutdown_waitobj_cb, handle); + return handle; +} + void -nm_utils_g_value_set_object_path_array (GValue *value, - GSList *objects, - NMUtilsObjectFunc filter_func, - gpointer user_data) +nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle) { - char **paths; - guint i; - GSList *iter; + g_return_if_fail (handle); - paths = g_new (char *, g_slist_length (objects) + 1); - for (i = 0, iter = objects; iter; iter = iter->next) { - NMExportedObject *object = iter->data; - const char *path; + nm_assert (G_IS_OBJECT (handle->watched_obj)); + nm_assert (nm_c_list_contains_entry (&_shutdown_waitobj_lst_head, handle, lst)); - path = nm_exported_object_get_path (object); - if (!path) - continue; - if (filter_func && !filter_func ((GObject *) object, user_data)) - continue; - paths[i++] = g_strdup (path); - } - paths[i] = NULL; - g_value_take_boxed (value, paths); + g_object_weak_unref (handle->watched_obj, _shutdown_waitobj_cb, handle); + _shutdown_waitobj_unregister (handle); } - -/*****************************************************************************/ |