summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-06-26 18:10:17 +0200
committerThomas Haller <thaller@redhat.com>2019-06-26 18:10:17 +0200
commitdd5c88b1cc5e6994f638e8731687c65a58a33767 (patch)
treea0fb372a27bd6623acca3f35b78cda2191be9d2b
parente4ce9bd7af6a39677ff1a1380906d18062abb24a (diff)
parent7b6f1c2d90e2ee96bf18ab14863ca4ad5c47d031 (diff)
downloadNetworkManager-dd5c88b1cc5e6994f638e8731687c65a58a33767.tar.gz
settings: merge branch 'th/various-settings-cleanup-3'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/187
-rw-r--r--CONTRIBUTING49
-rw-r--r--libnm-core/nm-connection.c50
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-simple-connection.c4
-rw-r--r--libnm-core/tests/test-secrets.c2
-rw-r--r--shared/nm-glib-aux/nm-c-list.h28
-rw-r--r--shared/nm-glib-aux/nm-glib.h12
-rw-r--r--shared/nm-glib-aux/nm-io-utils.c23
-rw-r--r--shared/nm-glib-aux/nm-io-utils.h4
-rw-r--r--shared/nm-glib-aux/nm-macros-internal.h24
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c29
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h3
-rw-r--r--src/NetworkManagerUtils.c34
-rw-r--r--src/NetworkManagerUtils.h7
-rw-r--r--src/devices/nm-device.c2
-rw-r--r--src/nm-core-utils.c2
-rw-r--r--src/nm-manager.c41
-rw-r--r--src/settings/nm-settings-connection.c137
-rw-r--r--src/settings/nm-settings.c6
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c10
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c25
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c45
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h6
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c6
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-plugin.c7
-rwxr-xr-xtools/create-exports-NetworkManager.sh2
27 files changed, 365 insertions, 196 deletions
diff --git a/CONTRIBUTING b/CONTRIBUTING
index 68026a81b5..febfdf0439 100644
--- a/CONTRIBUTING
+++ b/CONTRIBUTING
@@ -55,51 +55,66 @@ There are different kind of assertions. Use the one that is appropriate.
1) g_return_*() from glib. This is usually enabled in release builds and
can be disabled with G_DISABLE_CHECKS define. This uses g_log() with
G_LOG_LEVEL_CRITICAL level (which allows the program to continue,
- until G_DEBUG=fatal-criticals or G_DEBUG=fatal-warnings is set). As such,
- this is the preferred way for assertions that are commonly enabled.
-
- Make a mild attempt to work around such assertion failure, but don't try
- to hard. A failure of g_return_*() assertion might allow the process
- to continue, but there is no guarantee.
+ unless G_DEBUG=fatal-criticals or G_DEBUG=fatal-warnings is set). As such,
+ this is usually the preferred way for assertions that are supposed to be
+ enabled by default.
+
+ Optimally, after a g_return_*() failure the program can still continue. This is
+ also the reason why g_return_*() is preferable over g_assert().
+ For example, that is often not given for functions that return a GError, because
+ g_return_*() will return failure without setting the error output. That often leads
+ to a crash immidiately after, because the caller requires the GError to be set.
+ Make a reasonable effort so that an assertion failure may allow the process
+ to proceed. But don't put too much effort in it. After all, it's an assertion
+ failure that is not supposed to happen either way.
2) nm_assert() from NetworkManager. This is disabled by default in release
builds, but enabled if you build --with-more-assertions. See "WITH_MORE_ASSERTS"
define. This is preferred for assertions that are expensive to check or
- nor necessary to check frequently (stuff that is really not expected to
- fail). Use this deliberately and assume it's not present in production builds.
+ nor necessary to check frequently. It's also for conditions that can easily
+ verified to be true and where future refactoring is unlikley to break that
+ condition.
+ Use this deliberately and assume it is removed from production builds.
3) g_assert() from glib. This is used in unit tests and commonly enabled
in release builds. It can be disabled with G_DISABLE_ASSERT assert
define. Since this results in a hard crash on assertion failure, you
- should almost always prefer g_return_*() over this (except unit tests).
+ should almost always prefer g_return_*() over this (except in unit tests).
4) assert() from <assert.h>. It is usually enabled in release builds and
can be disabled with NDEBUG define. Don't use it in NetworkManager,
it's basically like g_assert().
-5) g_log() from glib. These are always compiled in, depending on the levels
+5) g_log() from glib. These are always compiled in, depending on the logging level
these are assertions too. G_LOG_LEVEL_ERROR aborts the program, G_LOG_LEVEL_CRITICAL
logs a critical warning (like g_return_*(), see G_DEBUG=fatal-criticals)
and G_LOG_LEVEL_WARNING logs a warning (see G_DEBUG=fatal-warnings).
G_LOG_LEVEL_DEBUG level is usually not printed, unless G_MESSAGES_DEBUG environment
is set.
- In general, avoid using g_log() in NetworkManager. We have nm-logging instead.
+ In general, avoid using g_log() in NetworkManager. We have nm-logging instead
+ which logs to syslog/systemd-journald.
From a library like libnm it might make sense to log warnings (if someting
is really wrong) or debug messages. But better don't. If it's important,
find a way to report the notification via the API to the caller. If it's
not important, keep silent.
+ In particular, don't use levels G_LOG_LEVEL_CRITICAL and G_LOG_LEVEL_WARNING because
+ these are effectively assertions and we want to run with G_DEBUG=fatal-warnings.
6) g_warn_if_*() from glib. These are always compiled in and log a G_LOG_LEVEL_WARNING
warning. Don't use this.
7) G_TYPE_CHECK_INSTANCE_CAST() from glib. Unless building with "WITH_MORE_ASSERTS",
- we disable G_DISABLE_CAST_CHECKS. This means, cast macros like NM_DEVICE(ptr)
- translate to plain C pointer casts. Use the cast macros deliberately, in production
- code they are cheap, with debugging enabled they assert that the pointer is valid.
+ we set G_DISABLE_CAST_CHECKS. This means, cast macros like NM_DEVICE(ptr)
+ translate to plain C pointer casts. Use such cast macros deliberately, in production
+ code they are cheap, with more asserts enabled the check that the pointer type is
+ suitable.
+
+Of course, every assertion failure is a bug, and calling it must have no side effects.
-Of course, every assertion failure is a bug, and they must not have side effects.
Theoretically, you are welcome to disable G_DISABLE_CHECKS and G_DISABLE_ASSERT
in production builds. In practice, nobody tests such a configuration, so beware.
-For testing, you also want to run NetworkManager with G_DEBUG=fatal-warnings
-to crash un critical and warn g_log() messages.
+For testing, you also want to run NetworkManager with environment variable
+G_DEBUG=fatal-warnings to crash upon G_LOG_LEVEL_CRITICAL and G_LOG_LEVEL_WARNING
+g_log() message. NetworkManager won't use these levels for regular logging
+but for assertions.
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index a2bd72b0d9..c45f29b467 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -1806,23 +1806,36 @@ _nmtst_connection_unchanging_secrets_updated_cb (NMConnection *connection, const
nm_assert_not_reached ();
}
+const char _nmtst_connection_unchanging_user_data = 0;
+
void
nmtst_connection_assert_unchanging (NMConnection *connection)
{
nm_assert (NM_IS_CONNECTION (connection));
+ if (g_signal_handler_find (connection,
+ G_SIGNAL_MATCH_DATA,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ (gpointer) &_nmtst_connection_unchanging_user_data) != 0) {
+ /* avoid connecting the assertion handler multiple times. */
+ return;
+ }
+
g_signal_connect (connection,
NM_CONNECTION_CHANGED,
G_CALLBACK (_nmtst_connection_unchanging_changed_cb),
- NULL);
+ (gpointer) &_nmtst_connection_unchanging_user_data);
g_signal_connect (connection,
NM_CONNECTION_SECRETS_CLEARED,
G_CALLBACK (_nmtst_connection_unchanging_changed_cb),
- NULL);
+ (gpointer) &_nmtst_connection_unchanging_user_data);
g_signal_connect (connection,
NM_CONNECTION_SECRETS_UPDATED,
G_CALLBACK (_nmtst_connection_unchanging_secrets_updated_cb),
- NULL);
+ (gpointer) &_nmtst_connection_unchanging_user_data);
}
#endif
@@ -1853,7 +1866,8 @@ nm_connection_update_secrets (NMConnection *connection,
GError **error)
{
NMSetting *setting;
- gboolean success = TRUE, updated = FALSE;
+ gboolean success = TRUE;
+ gboolean updated = FALSE;
GVariant *setting_dict = NULL;
GVariantIter iter;
const char *key;
@@ -1861,13 +1875,13 @@ nm_connection_update_secrets (NMConnection *connection,
int success_detail;
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
- g_return_val_if_fail ( g_variant_is_of_type (secrets, NM_VARIANT_TYPE_SETTING)
- || g_variant_is_of_type (secrets, NM_VARIANT_TYPE_CONNECTION), FALSE);
- if (error)
- g_return_val_if_fail (*error == NULL, FALSE);
full_connection = g_variant_is_of_type (secrets, NM_VARIANT_TYPE_CONNECTION);
- g_return_val_if_fail (setting_name != NULL || full_connection, FALSE);
+
+ g_return_val_if_fail ( full_connection
+ || g_variant_is_of_type (secrets, NM_VARIANT_TYPE_SETTING), FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+ g_return_val_if_fail (setting_name || full_connection, FALSE);
/* Empty @secrets means success */
if (g_variant_n_children (secrets) == 0)
@@ -1902,8 +1916,10 @@ nm_connection_update_secrets (NMConnection *connection,
g_clear_pointer (&setting_dict, g_variant_unref);
- if (success_detail == NM_SETTING_UPDATE_SECRET_ERROR)
+ if (success_detail == NM_SETTING_UPDATE_SECRET_ERROR) {
+ nm_assert (!error || *error);
return FALSE;
+ }
if (success_detail == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
updated = TRUE;
} else {
@@ -1923,17 +1939,27 @@ nm_connection_update_secrets (NMConnection *connection,
/* Update each setting with any secrets from the connection dictionary */
g_variant_iter_init (&iter, secrets);
while (g_variant_iter_next (&iter, "{&s@a{sv}}", &key, &setting_dict)) {
+ gs_free_error GError *local = NULL;
+
/* Update the secrets for this setting */
setting = nm_connection_get_setting_by_name (connection, key);
g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection);
- success_detail = _nm_setting_update_secrets (setting, setting_dict, error);
+ success_detail = _nm_setting_update_secrets (setting, setting_dict, error ? &local : NULL);
g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection);
g_variant_unref (setting_dict);
if (success_detail == NM_SETTING_UPDATE_SECRET_ERROR) {
- success = FALSE;
+ if (success) {
+ if (error) {
+ nm_assert (local);
+ g_propagate_error (error, g_steal_pointer (&local));
+ error = NULL;
+ } else
+ nm_assert (!local);
+ success = FALSE;
+ }
break;
}
if (success_detail == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index eaf29849cf..60e13937de 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -212,6 +212,7 @@ gboolean _nm_connection_ensure_normalized (NMConnection *connection,
gboolean _nm_connection_remove_setting (NMConnection *connection, GType setting_type);
#if NM_MORE_ASSERTS
+extern const char _nmtst_connection_unchanging_user_data;
void nmtst_connection_assert_unchanging (NMConnection *connection);
#else
static inline void
diff --git a/libnm-core/nm-simple-connection.c b/libnm-core/nm-simple-connection.c
index d281aa9725..f58f145f91 100644
--- a/libnm-core/nm-simple-connection.c
+++ b/libnm-core/nm-simple-connection.c
@@ -141,6 +141,10 @@ nm_simple_connection_new_clone (NMConnection *connection)
static void
dispose (GObject *object)
{
+#if NM_MORE_ASSERTS
+ g_signal_handlers_disconnect_by_data (object, (gpointer) &_nmtst_connection_unchanging_user_data);
+#endif
+
nm_connection_clear_secrets (NM_CONNECTION (object));
G_OBJECT_CLASS (nm_simple_connection_parent_class)->dispose (object);
diff --git a/libnm-core/tests/test-secrets.c b/libnm-core/tests/test-secrets.c
index 22183073e9..d657a43c4e 100644
--- a/libnm-core/tests/test-secrets.c
+++ b/libnm-core/tests/test-secrets.c
@@ -648,7 +648,7 @@ test_update_secrets_null_setting_name_with_setting_hash (void)
secrets = build_wep_secrets (wepkey);
- NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (setting_name != NULL || full_connection));
+ NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (setting_name || full_connection));
success = nm_connection_update_secrets (connection, NULL, secrets, &error);
g_test_assert_expected_messages ();
g_assert_no_error (error);
diff --git a/shared/nm-glib-aux/nm-c-list.h b/shared/nm-glib-aux/nm-c-list.h
index d835bbc1d4..36f1ff755b 100644
--- a/shared/nm-glib-aux/nm-c-list.h
+++ b/shared/nm-glib-aux/nm-c-list.h
@@ -101,12 +101,24 @@ nm_c_list_elem_find_first (CList *head, gconstpointer needle)
/*****************************************************************************/
+/**
+ * nm_c_list_move_before:
+ * @lst: the list element to which @elem will be prepended.
+ * @elem: the list element to move.
+ *
+ * This unlinks @elem from the current list and linkes it before
+ * @lst. This is like c_list_link_before(), except that @elem must
+ * be initialized and linked. Note that @elem may be linked in @lst
+ * or in another list. In both cases it gets moved.
+ *
+ * Returns: %TRUE if there were any changes. %FALSE if elem was already
+ * linked at the right place.
+ */
static inline gboolean
nm_c_list_move_before (CList *lst, CList *elem)
{
nm_assert (lst);
nm_assert (elem);
- nm_assert (c_list_contains (lst, elem));
if ( lst != elem
&& lst->prev != elem) {
@@ -118,12 +130,24 @@ nm_c_list_move_before (CList *lst, CList *elem)
}
#define nm_c_list_move_tail(lst, elem) nm_c_list_move_before (lst, elem)
+/**
+ * nm_c_list_move_after:
+ * @lst: the list element to which @elem will be prepended.
+ * @elem: the list element to move.
+ *
+ * This unlinks @elem from the current list and linkes it after
+ * @lst. This is like c_list_link_after(), except that @elem must
+ * be initialized and linked. Note that @elem may be linked in @lst
+ * or in another list. In both cases it gets moved.
+ *
+ * Returns: %TRUE if there were any changes. %FALSE if elem was already
+ * linked at the right place.
+ */
static inline gboolean
nm_c_list_move_after (CList *lst, CList *elem)
{
nm_assert (lst);
nm_assert (elem);
- nm_assert (c_list_contains (lst, elem));
if ( lst != elem
&& lst->next != elem) {
diff --git a/shared/nm-glib-aux/nm-glib.h b/shared/nm-glib-aux/nm-glib.h
index 77a0913899..bdb7ea5b3e 100644
--- a/shared/nm-glib-aux/nm-glib.h
+++ b/shared/nm-glib-aux/nm-glib.h
@@ -522,10 +522,18 @@ _nm_g_variant_new_printf (const char *format_string, ...)
/*****************************************************************************/
-#if !GLIB_CHECK_VERSION (2, 56, 0)
+/* Recent glib also casts the results to typeof(Obj), but only if
+ *
+ * ( defined(g_has_typeof) && GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_56 )
+ *
+ * Since we build NetworkManager with older GLIB_VERSION_MAX_ALLOWED, it's
+ * not taking effect.
+ *
+ * Override this. */
+#undef g_object_ref
+#undef g_object_ref_sink
#define g_object_ref(Obj) ((typeof(Obj)) g_object_ref (Obj))
#define g_object_ref_sink(Obj) ((typeof(Obj)) g_object_ref_sink (Obj))
-#endif
/*****************************************************************************/
diff --git a/shared/nm-glib-aux/nm-io-utils.c b/shared/nm-glib-aux/nm-io-utils.c
index 7b9ca0218a..23133ec568 100644
--- a/shared/nm-glib-aux/nm-io-utils.c
+++ b/shared/nm-glib-aux/nm-io-utils.c
@@ -436,3 +436,26 @@ nm_utils_file_set_contents (const char *filename,
return TRUE;
}
+
+/**
+ * nm_utils_file_stat:
+ * @filename: the filename to stat.
+ * @out_st: (allow-none) (out): if given, this will be passed to stat().
+ *
+ * Just wraps stat() and gives the errno number as function result instead
+ * of setting the errno (though, errno is also set). It's only for convenience
+ * with
+ *
+ * if (nm_utils_file_stat (filename, NULL) == -ENOENT) {
+ * }
+ *
+ * Returns: 0 on success a negative errno on failure. */
+int
+nm_utils_file_stat (const char *filename, struct stat *out_st)
+{
+ struct stat st;
+
+ if (stat (filename, out_st ?: &st) != 0)
+ return -NM_ERRNO_NATIVE (errno);
+ return 0;
+}
diff --git a/shared/nm-glib-aux/nm-io-utils.h b/shared/nm-glib-aux/nm-io-utils.h
index 6037242b02..121fc481d9 100644
--- a/shared/nm-glib-aux/nm-io-utils.h
+++ b/shared/nm-glib-aux/nm-io-utils.h
@@ -59,4 +59,8 @@ gboolean nm_utils_file_set_contents (const char *filename,
mode_t mode,
GError **error);
+struct stat;
+
+int nm_utils_file_stat (const char *filename, struct stat *out_st);
+
#endif /* __NM_IO_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h
index 5b594a2ab5..d2210db006 100644
--- a/shared/nm-glib-aux/nm-macros-internal.h
+++ b/shared/nm-glib-aux/nm-macros-internal.h
@@ -1160,6 +1160,30 @@ nm_g_object_unref (gpointer obj)
#define nm_clear_g_object(pp) \
nm_clear_pointer (pp, g_object_unref)
+/**
+ * nm_clear_error:
+ * @err: a pointer to pointer to a #GError.
+ *
+ * This is like g_clear_error(). The only difference is
+ * that this is an inline function.
+ */
+static inline void
+nm_clear_error (GError **err)
+{
+ if (err && *err) {
+ g_error_free (*err);
+ *err = NULL;
+ }
+}
+
+/* Patch g_clear_error() to use nm_clear_error(), which is inlineable
+ * and visible to the compiler. For example gs_free_error attribute only
+ * frees the error after checking that it's not %NULL. So, in many cases
+ * the compiler knows that gs_free_error has no effect and can optimize
+ * the call away. By making g_clear_error() inlineable, we give the compiler
+ * more chance to detect that the function actually has no effect. */
+#define g_clear_error(ptr) nm_clear_error(ptr)
+
static inline gboolean
nm_clear_g_source (guint *id)
{
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 49037ed7b4..472a4c484f 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -2282,6 +2282,35 @@ nm_utils_hash_keys_to_array (GHashTable *hash,
return keys;
}
+gboolean
+nm_utils_hashtable_same_keys (const GHashTable *a,
+ const GHashTable *b)
+{
+ GHashTableIter h;
+ const char *k;
+
+ if (a == b)
+ return TRUE;
+ if (!a || !b)
+ return FALSE;
+ if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b))
+ return FALSE;
+
+ g_hash_table_iter_init (&h, (GHashTable *) a);
+ while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) {
+ if (!g_hash_table_contains ((GHashTable *) b, k))
+ return FALSE;
+ }
+
+#if NM_MORE_ASSERTS > 5
+ g_hash_table_iter_init (&h, (GHashTable *) b);
+ while (g_hash_table_iter_next (&h, (gpointer) &k, NULL))
+ nm_assert (g_hash_table_contains ((GHashTable *) a, k));
+#endif
+
+ return TRUE;
+}
+
char **
nm_utils_strv_make_deep_copied (const char **strv)
{
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index a8f2966b38..e65d1be683 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -966,6 +966,9 @@ nm_utils_strdict_get_keys (const GHashTable *hash,
out_length);
}
+gboolean nm_utils_hashtable_same_keys (const GHashTable *a,
+ const GHashTable *b);
+
char **nm_utils_strv_make_deep_copied (const char **strv);
char **nm_utils_strv_make_deep_copied_n (const char **strv, gsize len);
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index a070d50c2a..3618e32f51 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -959,7 +959,8 @@ nm_ip_routing_rule_to_platform (const NMIPRoutingRule *rule,
struct _NMShutdownWaitObjHandle {
CList lst;
GObject *watched_obj;
- const char *msg_reason;
+ char *msg_reason;
+ bool free_msg_reason:1;
};
static CList _shutdown_waitobj_lst_head;
@@ -968,6 +969,8 @@ static void
_shutdown_waitobj_unregister (NMShutdownWaitObjHandle *handle)
{
c_list_unlink_stale (&handle->lst);
+ if (handle->free_msg_reason)
+ g_free (handle->msg_reason);
g_slice_free (NMShutdownWaitObjHandle, handle);
/* FIXME(shutdown): check whether the object list is empty, and
@@ -986,13 +989,14 @@ _shutdown_waitobj_cb (gpointer user_data,
}
/**
- * _nm_shutdown_wait_obj_register:
+ * nm_shutdown_wait_obj_register_full:
* @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.
+ * @msg_reason: a reason message, for debugging and logging purposes.
+ * @free_msg_reason: if %TRUE, then ownership of @msg_reason will be taken
+ * and the string will be freed with g_free() afterwards. If %FALSE,
+ * the caller must ensure that @msg_reason string outlives the watched
+ * objects (e.g. being a static strings).
*
* Keep track of @watched_obj until it gets destroyed. During shutdown,
* we wait until all watched objects are destroyed. This is useful, if
@@ -1009,8 +1013,9 @@ _shutdown_waitobj_cb (gpointer user_data,
* once it gets destroyed.
*/
NMShutdownWaitObjHandle *
-_nm_shutdown_wait_obj_register (GObject *watched_obj,
- const char *msg_reason)
+nm_shutdown_wait_obj_register_full (GObject *watched_obj,
+ char *msg_reason,
+ gboolean free_msg_reason)
{
NMShutdownWaitObjHandle *handle;
@@ -1020,11 +1025,14 @@ _nm_shutdown_wait_obj_register (GObject *watched_obj,
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;
+ *handle = (NMShutdownWaitObjHandle) {
+ /* depending on @free_msg_reason, we take ownership of @msg_reason.
+ * In either case, we just reference the string without cloning
+ * it. */
+ .watched_obj = watched_obj,
+ .msg_reason = msg_reason,
+ .free_msg_reason = free_msg_reason,
+ };
c_list_link_tail (&_shutdown_waitobj_lst_head, &handle->lst);
g_object_weak_ref (watched_obj, _shutdown_waitobj_cb, handle);
return handle;
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 5e3f6673c4..778dc00176 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -89,10 +89,11 @@ NMPlatformRoutingRule *nm_ip_routing_rule_to_platform (const NMIPRoutingRule *ru
typedef struct _NMShutdownWaitObjHandle NMShutdownWaitObjHandle;
-NMShutdownWaitObjHandle *_nm_shutdown_wait_obj_register (GObject *watched_obj,
- const char *msg_reason);
+NMShutdownWaitObjHandle *nm_shutdown_wait_obj_register_full (GObject *watched_obj,
+ char *msg_reason,
+ gboolean free_msg_reason);
-#define nm_shutdown_wait_obj_register(watched_obj, msg_reason) _nm_shutdown_wait_obj_register((watched_obj), (""msg_reason""))
+#define nm_shutdown_wait_obj_register(watched_obj, msg_reason) nm_shutdown_wait_obj_register_full((watched_obj), (""msg_reason""), FALSE)
void nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 8fe3e5776f..abcff229bf 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -5753,7 +5753,7 @@ nm_device_complete_connection (NMDevice *self,
error))
return FALSE;
- if (!nm_connection_verify (connection, error))
+ if (!nm_connection_normalize (connection, NULL, NULL, error))
return FALSE;
return nm_device_check_connection_compatible (self, connection, error);
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 04d2074af0..6784551675 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -126,6 +126,8 @@ static void
_nm_singleton_instance_weak_cb (gpointer data,
GObject *where_the_object_was)
{
+ nm_assert (g_slist_find (_singletons, where_the_object_was));
+
_singletons = g_slist_remove (_singletons, where_the_object_was);
}
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 8960079b11..c961ebc045 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -817,14 +817,14 @@ _delete_volatile_connection_do (NMManager *self,
if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
return;
+ if (!nm_settings_has_connection (priv->settings, connection))
+ return;
if (active_connection_find (self,
connection,
NULL,
NM_ACTIVE_CONNECTION_STATE_DEACTIVATED,
NULL))
return;
- if (!nm_settings_has_connection (priv->settings, connection))
- return;
_LOGD (LOGD_DEVICE, "volatile connection disconnected. Deleting connection '%s' (%s)",
nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection));
@@ -2064,8 +2064,14 @@ static void
connection_changed (NMManager *self,
NMSettingsConnection *sett_conn)
{
+ NMConnection *connection;
NMDevice *device;
- NMConnection *connection = nm_settings_connection_get_connection (sett_conn);
+
+ if (NM_FLAGS_HAS (nm_settings_connection_get_flags (sett_conn),
+ NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
+ return;
+
+ connection = nm_settings_connection_get_connection (sett_conn);
if (!nm_connection_is_virtual (connection))
return;
@@ -2094,33 +2100,22 @@ connection_updated_cb (NMSettings *settings,
gboolean by_user,
NMManager *self)
{
- if (by_user)
- connection_changed (self, sett_conn);
+ connection_changed (self, sett_conn);
}
/*****************************************************************************/
-typedef struct {
- CList delete_volatile_connection_lst;
- NMSettingsConnection *connection;
-} DeleteVolatileConnectionData;
-
static void
_delete_volatile_connection_all (NMManager *self, gboolean do_delete)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- CList *lst;
- DeleteVolatileConnectionData *data;
+ NMCListElem *elem;
- while ((lst = c_list_first (&priv->delete_volatile_connection_lst_head))) {
+ while ((elem = c_list_first_entry (&priv->delete_volatile_connection_lst_head, NMCListElem, lst))) {
gs_unref_object NMSettingsConnection *connection = NULL;
- data = c_list_entry (lst,
- DeleteVolatileConnectionData,
- delete_volatile_connection_lst);
- connection = data->connection;
- c_list_unlink_stale (&data->delete_volatile_connection_lst);
- g_slice_free (DeleteVolatileConnectionData, data);
+ connection = elem->data;
+ nm_c_list_elem_free (elem);
if (do_delete)
_delete_volatile_connection_do (self, connection);
@@ -2145,7 +2140,6 @@ connection_flags_changed (NMSettings *settings,
{
NMManager *self = user_data;
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- DeleteVolatileConnectionData *data;
if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection),
NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE))
@@ -2157,9 +2151,8 @@ connection_flags_changed (NMSettings *settings,
return;
}
- data = g_slice_new (DeleteVolatileConnectionData);
- data->connection = g_object_ref (connection);
- c_list_link_tail (&priv->delete_volatile_connection_lst_head, &data->delete_volatile_connection_lst);
+ c_list_link_tail (&priv->delete_volatile_connection_lst_head,
+ &nm_c_list_elem_new_stale (g_object_ref (connection))->lst);
if (!priv->delete_volatile_connection_idle_id)
priv->delete_volatile_connection_idle_id = g_idle_add (_delete_volatile_connection_cb, self);
}
@@ -5529,6 +5522,8 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
goto error;
}
+ nm_assert (_nm_connection_verify (incompl_conn, NULL) == NM_SETTING_VERIFY_SUCCESS);
+
active = _new_active_connection (self,
is_vpn,
NULL,
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index dfe10459c4..663e630656 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -111,7 +111,7 @@ typedef struct _NMSettingsConnectionPrivate {
* to re-read them from disk which defeats the purpose of having the
* connection in-memory at all.
*/
- NMConnection *system_secrets;
+ GVariant *system_secrets;
/* Caches secrets from agents during the activation process; if new system
* secrets are returned from an agent, they get written out to disk,
@@ -119,7 +119,7 @@ typedef struct _NMSettingsConnectionPrivate {
* secrets, and would wipe out any agent-owned or not-saved secrets the
* agent also returned.
*/
- NMConnection *agent_secrets;
+ GVariant *agent_secrets;
char *filename;
@@ -316,30 +316,36 @@ static void
update_system_secrets_cache (NMSettingsConnection *self)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+ gs_unref_object NMConnection *connection_cloned = NULL;
- if (priv->system_secrets)
- g_object_unref (priv->system_secrets);
- priv->system_secrets = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self));
+ nm_clear_pointer (&priv->system_secrets, g_variant_unref);
+
+ connection_cloned = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self));
/* Clear out non-system-owned and not-saved secrets */
- _nm_connection_clear_secrets_by_secret_flags (priv->system_secrets,
+ _nm_connection_clear_secrets_by_secret_flags (connection_cloned,
NM_SETTING_SECRET_FLAG_NONE);
+
+ priv->system_secrets = nm_g_variant_ref_sink (nm_connection_to_dbus (connection_cloned, NM_CONNECTION_SERIALIZE_ONLY_SECRETS));
}
static void
update_agent_secrets_cache (NMSettingsConnection *self, NMConnection *new)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+ gs_unref_object NMConnection *connection_cloned = NULL;
- if (priv->agent_secrets)
- g_object_unref (priv->agent_secrets);
- priv->agent_secrets = nm_simple_connection_new_clone ( new
- ?: nm_settings_connection_get_connection (self));
+ nm_clear_pointer (&priv->agent_secrets, g_variant_unref);
+
+ connection_cloned = nm_simple_connection_new_clone ( new
+ ?: nm_settings_connection_get_connection (self));
/* Clear out non-system-owned secrets */
- _nm_connection_clear_secrets_by_secret_flags (priv->agent_secrets,
+ _nm_connection_clear_secrets_by_secret_flags (connection_cloned,
NM_SETTING_SECRET_FLAG_NOT_SAVED
| NM_SETTING_SECRET_FLAG_AGENT_OWNED);
+
+ priv->agent_secrets = nm_g_variant_ref_sink (nm_connection_to_dbus (connection_cloned, NM_CONNECTION_SERIALIZE_ONLY_SECRETS));
}
static void
@@ -350,9 +356,7 @@ secrets_cleared_cb (NMConnection *connection, NMSettingsConnection *self)
/* Clear agent secrets when connection's secrets are cleared since agent
* secrets are transient.
*/
- if (priv->agent_secrets)
- g_object_unref (priv->agent_secrets);
- priv->agent_secrets = NULL;
+ nm_clear_pointer (&priv->agent_secrets, g_variant_unref);
}
static void
@@ -572,25 +576,23 @@ nm_settings_connection_update (NMSettingsConnection *self,
* in the replacement connection data if it was eg reread from disk.
*/
if (priv->agent_secrets) {
- GVariant *dict;
-
- dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
- if (dict) {
- (void) nm_connection_update_secrets (nm_settings_connection_get_connection (self), NULL, dict, NULL);
- g_variant_unref (dict);
- }
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
+ nm_connection_update_secrets (nm_settings_connection_get_connection (self), NULL, priv->agent_secrets, NULL);
+ }
+ if (con_agent_secrets) {
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
+ nm_connection_update_secrets (nm_settings_connection_get_connection (self), NULL, con_agent_secrets, NULL);
}
- if (con_agent_secrets)
- (void) nm_connection_update_secrets (nm_settings_connection_get_connection (self), NULL, con_agent_secrets, NULL);
}
/* Apply agent-owned secrets from the new connection so that
* they can be sent to agents */
if (new_agent_secrets) {
- (void) nm_connection_update_secrets (nm_settings_connection_get_connection (self),
- NULL,
- new_agent_secrets,
- NULL);
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
+ nm_connection_update_secrets (nm_settings_connection_get_connection (self),
+ NULL,
+ new_agent_secrets,
+ NULL);
}
nm_settings_connection_recheck_visibility (self);
@@ -857,6 +859,7 @@ nm_settings_connection_new_secrets (NMSettingsConnection *self,
return FALSE;
}
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
if (!nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, secrets, error))
return FALSE;
@@ -889,7 +892,7 @@ get_secrets_done_cb (NMAgentManager *manager,
NMSettingsConnectionPrivate *priv;
NMConnection *applied_connection;
gs_free_error GError *local = NULL;
- GVariant *dict = NULL;
+ gs_unref_variant GVariant *system_secrets = NULL;
gboolean agent_had_system = FALSE;
ForEachSecretFlags cmp_flags = { NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_SECRET_FLAG_NONE };
@@ -952,12 +955,17 @@ get_secrets_done_cb (NMAgentManager *manager,
setting_name,
call_id);
- if (priv->system_secrets)
- dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
+ system_secrets = nm_g_variant_ref (priv->system_secrets);
/* Update the connection with our existing secrets from backing storage */
nm_connection_clear_secrets (nm_settings_connection_get_connection (self));
- if (!dict || nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, dict, &local)) {
+
+ if ( !system_secrets
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
+ || nm_connection_update_secrets (nm_settings_connection_get_connection (self),
+ setting_name,
+ system_secrets,
+ &local)) {
gs_unref_variant GVariant *filtered_secrets = NULL;
/* Update the connection with the agent's secrets; by this point if any
@@ -966,6 +974,7 @@ get_secrets_done_cb (NMAgentManager *manager,
* system secrets.
*/
filtered_secrets = validate_secret_flags (nm_settings_connection_get_connection (self), secrets, &cmp_flags);
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
if (nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, filtered_secrets, &local)) {
/* Now that all secrets are updated, copy and cache new secrets,
* then save them to backing storage.
@@ -1023,7 +1032,8 @@ get_secrets_done_cb (NMAgentManager *manager,
nm_connection_clear_secrets (applied_connection);
- if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) {
+ if ( !system_secrets
+ || nm_connection_update_secrets (applied_connection, setting_name, system_secrets, NULL)) {
gs_unref_variant GVariant *filtered_secrets = NULL;
filtered_secrets = validate_secret_flags (applied_connection, secrets, &cmp_flags);
@@ -1033,8 +1043,6 @@ get_secrets_done_cb (NMAgentManager *manager,
_get_secrets_info_callback (call_id, agent_username, setting_name, local);
g_clear_error (&local);
- if (dict)
- g_variant_unref (dict);
out:
_get_secrets_info_free (call_id);
@@ -1095,7 +1103,6 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
gpointer callback_data)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
- GVariant *existing_secrets = NULL;
NMAgentManagerCallId call_id_a;
gs_free char *joined_hints = NULL;
NMSettingsConnectionCallId *call_id;
@@ -1132,14 +1139,6 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
goto schedule_dummy;
}
- /* Use priv->system_secrets to work around the fact that nm_connection_clear_secrets()
- * will clear secrets on this object's settings.
- */
- if (priv->system_secrets)
- existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
- if (existing_secrets)
- g_variant_ref_sink (existing_secrets);
-
/* we remember the current version-id of the secret-agents. The version-id is strictly increasing,
* as new agents register the number. We know hence, that this request was made against a certain
* set of secret-agents.
@@ -1147,19 +1146,20 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
* Then we know that the this request probably did not yet include the latest secret-agent. */
priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id (priv->agent_mgr);
+ /* Use priv->system_secrets to work around the fact that nm_connection_clear_secrets()
+ * will clear secrets on this object's settings.
+ */
call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr,
nm_dbus_object_get_path (NM_DBUS_OBJECT (self)),
nm_settings_connection_get_connection (self),
subject,
- existing_secrets,
+ priv->system_secrets,
setting_name,
flags,
hints,
get_secrets_done_cb,
call_id);
- g_assert (call_id_a);
- if (existing_secrets)
- g_variant_unref (existing_secrets);
+ nm_assert (call_id_a);
_LOGD ("(%s:%p) secrets requested flags 0x%X hints '%s'",
setting_name,
@@ -1465,28 +1465,6 @@ typedef struct {
} UpdateInfo;
static void
-cached_secrets_to_connection (NMSettingsConnection *self, NMConnection *connection)
-{
- NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
- GVariant *secrets_dict;
-
- if (priv->agent_secrets) {
- secrets_dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
- if (secrets_dict) {
- (void) nm_connection_update_secrets (connection, NULL, secrets_dict, NULL);
- g_variant_unref (secrets_dict);
- }
- }
- if (priv->system_secrets) {
- secrets_dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
- if (secrets_dict) {
- (void) nm_connection_update_secrets (connection, NULL, secrets_dict, NULL);
- g_variant_unref (secrets_dict);
- }
- }
-}
-
-static void
update_complete (NMSettingsConnection *self,
UpdateInfo *info,
GError *error)
@@ -1519,6 +1497,7 @@ update_auth_cb (NMSettingsConnection *self,
GError *error,
gpointer data)
{
+ NMSettingsConnectionPrivate *priv;
UpdateInfo *info = data;
NMSettingsConnectionCommitReason commit_reason;
gs_free_error GError *local = NULL;
@@ -1530,13 +1509,18 @@ update_auth_cb (NMSettingsConnection *self,
return;
}
+ priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+
if (info->new_settings) {
if (!_nm_connection_aggregate (info->new_settings, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL)) {
/* If the new connection has no secrets, we do not want to remove all
* secrets, rather we keep all the existing ones. Do that by merging
* them in to the new connection.
*/
- cached_secrets_to_connection (self, info->new_settings);
+ if (priv->agent_secrets)
+ nm_connection_update_secrets (info->new_settings, NULL, priv->agent_secrets, NULL);
+ if (priv->system_secrets)
+ nm_connection_update_secrets (info->new_settings, NULL, priv->system_secrets, NULL);
} else {
/* Cache the new secrets from the agent, as stuff like inotify-triggered
* changes to connection's backing config files will blow them away if
@@ -2020,11 +2004,12 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self,
}
/* Clear secrets in connection and caches */
+
+ /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */
nm_connection_clear_secrets (nm_settings_connection_get_connection (self));
- if (priv->system_secrets)
- nm_connection_clear_secrets (priv->system_secrets);
- if (priv->agent_secrets)
- nm_connection_clear_secrets (priv->agent_secrets);
+
+ nm_clear_pointer (&priv->system_secrets, g_variant_unref);
+ nm_clear_pointer (&priv->agent_secrets, g_variant_unref);
/* Tell agents to remove secrets for this connection */
nm_agent_manager_delete_secrets (priv->agent_mgr,
@@ -2785,8 +2770,8 @@ dispose (GObject *object)
nm_connection_clear_secrets (priv->connection);
}
- g_clear_object (&priv->system_secrets);
- g_clear_object (&priv->agent_secrets);
+ nm_clear_pointer (&priv->system_secrets, g_variant_unref);
+ nm_clear_pointer (&priv->agent_secrets, g_variant_unref);
g_clear_pointer (&priv->seen_bssids, g_hash_table_destroy);
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 4d1915e24c..6fbda5274b 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -720,7 +720,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (context));
/* Connection must be valid, of course */
- if (!nm_connection_verify (connection, &tmp_error)) {
+ if (_nm_connection_verify (connection, &tmp_error) != NM_SETTING_VERIFY_SUCCESS) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
"The connection was invalid: %s",
@@ -1255,6 +1255,10 @@ add_plugin (NMSettings *self,
priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
+ nm_shutdown_wait_obj_register_full (G_OBJECT (plugin),
+ g_strdup_printf ("%s-settings-plugin", pname),
+ TRUE);
+
_LOGI ("Loaded settings plugin: %s (%s%s%s)",
pname,
NM_PRINT_FMT_QUOTED (path, "\"", path, "\"", "internal"));
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c
index 9abe26eebf..5caa861de9 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c
@@ -206,6 +206,8 @@ commit_changes (NMSettingsConnection *connection,
if (!nms_ifcfg_rh_writer_write_connection (new_connection,
IFCFG_DIR,
filename,
+ NULL,
+ NULL,
&ifcfg_path,
&reread,
&reread_same,
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
index 14e4108f66..6375b6cc14 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
@@ -79,12 +79,6 @@ G_DEFINE_TYPE (SettingsPluginIfcfg, settings_plugin_ifcfg, NM_TYPE_SETTINGS_PLUG
/*****************************************************************************/
-static SettingsPluginIfcfg *settings_plugin_ifcfg_get (void);
-
-NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfcfg, settings_plugin_ifcfg_get, SETTINGS_TYPE_PLUGIN_IFCFG);
-
-/*****************************************************************************/
-
#define _NMLOG_DOMAIN LOGD_SETTINGS
#define _NMLOG(level, ...) \
G_STMT_START { \
@@ -600,7 +594,7 @@ add_connection (NMSettingsPlugin *config,
gs_unref_object NMConnection *reread = NULL;
if (save_to_disk) {
- if (!nms_ifcfg_rh_writer_write_connection (connection, IFCFG_DIR, NULL, &path, &reread, NULL, error))
+ if (!nms_ifcfg_rh_writer_write_connection (connection, IFCFG_DIR, NULL, NULL, NULL, &path, &reread, NULL, error))
return NULL;
} else {
if (!nms_ifcfg_rh_writer_can_write_connection (connection, error))
@@ -984,5 +978,5 @@ settings_plugin_ifcfg_class_init (SettingsPluginIfcfgClass *klass)
G_MODULE_EXPORT NMSettingsPlugin *
nm_settings_plugin_factory (void)
{
- return NM_SETTINGS_PLUGIN (g_object_ref (settings_plugin_ifcfg_get ()));
+ return g_object_new (SETTINGS_TYPE_PLUGIN_IFCFG, NULL);
}
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
index 9a05572660..038f3dacc9 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
@@ -316,36 +316,41 @@ utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg)
char *
utils_detect_ifcfg_path (const char *path, gboolean only_ifcfg)
{
- gs_free char *base = NULL;
- char *ptr, *ifcfg = NULL;
+ const char *base;
g_return_val_if_fail (path != NULL, NULL);
if (utils_should_ignore_file (path, only_ifcfg))
return NULL;
- base = g_path_get_basename (path);
+ base = strrchr (path, '/');
+ if (!base)
+ base = path;
+ else
+ base += 1;
- if (strncmp (base, IFCFG_TAG, NM_STRLEN (IFCFG_TAG)) == 0) {
+ if (NM_STR_HAS_PREFIX (base, IFCFG_TAG)) {
if (base[NM_STRLEN (IFCFG_TAG)] == '\0')
return NULL;
if (utils_is_ifcfg_alias_file (base, NULL)) {
+ gs_free char *ifcfg = NULL;
+ char *ptr;
+
ifcfg = g_strdup (path);
ptr = strrchr (ifcfg, ':');
- if (ptr && ptr > ifcfg) {
+ if ( ptr
+ && ptr > ifcfg
+ && !strchr (ptr, '/')) {
*ptr = '\0';
if (g_file_test (ifcfg, G_FILE_TEST_EXISTS)) {
/* the file has a colon, so it is probably an alias.
* To be ~more~ certain that this is an alias file,
* check whether a corresponding base file exists. */
- if (only_ifcfg) {
- g_free (ifcfg);
+ if (only_ifcfg)
return NULL;
- }
- return ifcfg;
+ return g_steal_pointer (&ifcfg);
}
}
- g_free (ifcfg);
}
return g_strdup (path);
}
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index fc5b1672d5..e6a08f7158 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -3024,6 +3024,8 @@ static gboolean
do_write_construct (NMConnection *connection,
const char *ifcfg_dir,
const char *filename,
+ NMSIfcfgRHWriterAllowFilenameCb allow_filename_cb,
+ gpointer allow_filename_user_data,
shvarFile **out_ifcfg,
GHashTable **out_blobs,
GHashTable **out_secrets,
@@ -3067,30 +3069,31 @@ do_write_construct (NMConnection *connection,
ifcfg_name = g_strdup (filename);
} else if (ifcfg_dir) {
- char *escaped;
+ gs_free char *escaped = NULL;
+ int i_path;
escaped = escape_id (nm_setting_connection_get_id (s_con));
- ifcfg_name = g_strdup_printf ("%s/ifcfg-%s", ifcfg_dir, escaped);
- /* If a file with this path already exists then we need another name.
- * Multiple connections can have the same ID (ie if two connections with
- * the same ID are visible to different users) but of course can't have
- * the same path.
- */
- if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS)) {
- guint32 idx = 0;
-
- nm_clear_g_free (&ifcfg_name);
- while (idx++ < 500) {
- ifcfg_name = g_strdup_printf ("%s/ifcfg-%s-%u", ifcfg_dir, escaped, idx);
- if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS) == FALSE)
- break;
- nm_clear_g_free (&ifcfg_name);
- }
+ for (i_path = 0; i_path < 10000; i_path++) {
+ gs_free char *path_candidate = NULL;
+
+ if (i_path == 0)
+ path_candidate = g_strdup_printf ("%s/ifcfg-%s", ifcfg_dir, escaped);
+ else
+ path_candidate = g_strdup_printf ("%s/ifcfg-%s-%d", ifcfg_dir, escaped, i_path);
+
+ if ( allow_filename_cb
+ && !allow_filename_cb (path_candidate, allow_filename_user_data))
+ continue;
+
+ if (g_file_test (path_candidate, G_FILE_TEST_EXISTS))
+ continue;
+
+ ifcfg_name = g_steal_pointer (&path_candidate);
+ break;
}
- g_free (escaped);
- if (ifcfg_name == NULL) {
+ if (!ifcfg_name) {
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"Failed to find usable ifcfg file name");
return FALSE;
@@ -3377,6 +3380,8 @@ gboolean
nms_ifcfg_rh_writer_write_connection (NMConnection *connection,
const char *ifcfg_dir,
const char *filename,
+ NMSIfcfgRHWriterAllowFilenameCb allow_filename_cb,
+ gpointer allow_filename_user_data,
char **out_filename,
NMConnection **out_reread,
gboolean *out_reread_same,
@@ -3396,6 +3401,8 @@ nms_ifcfg_rh_writer_write_connection (NMConnection *connection,
if (!do_write_construct (connection,
ifcfg_dir,
filename,
+ allow_filename_cb,
+ allow_filename_user_data,
&ifcfg,
&blobs,
&secrets,
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h
index 15bf4386a6..0902daeef1 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h
@@ -22,12 +22,18 @@
#include "nm-connection.h"
+
+typedef gboolean (*NMSIfcfgRHWriterAllowFilenameCb) (const char *check_filename,
+ gpointer allow_filename_user_data);
+
gboolean nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection,
GError **error);
gboolean nms_ifcfg_rh_writer_write_connection (NMConnection *connection,
const char *ifcfg_dir,
const char *filename,
+ NMSIfcfgRHWriterAllowFilenameCb allow_filename_cb,
+ gpointer allow_filename_user_data,
char **out_filename,
NMConnection **out_reread,
gboolean *out_reread_same,
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 97bba2f14c..9792e20ecd 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -238,7 +238,7 @@ _assert_expected_content (NMConnection *connection, const char *filename, const
g_assert (_ifcfg_dir && _ifcfg_dir[0]); \
g_assert (_filename && _filename[0]); \
\
- _success = nms_ifcfg_rh_writer_write_connection (_connection, _ifcfg_dir, _filename, NULL, _out_reread, _out_reread_same, &_error); \
+ _success = nms_ifcfg_rh_writer_write_connection (_connection, _ifcfg_dir, _filename, NULL, NULL, NULL, _out_reread, _out_reread_same, &_error); \
nmtst_assert_success (_success, _error); \
_assert_expected_content (_connection, _filename, _expected); \
} G_STMT_END
@@ -319,6 +319,8 @@ _writer_new_connection_reread (NMConnection *connection,
success = nms_ifcfg_rh_writer_write_connection (con_verified,
ifcfg_dir,
NULL,
+ NULL,
+ NULL,
&filename,
reread,
out_reread_same,
@@ -394,6 +396,8 @@ _writer_new_connection_fail (NMConnection *connection,
success = nms_ifcfg_rh_writer_write_connection (connection_normalized,
ifcfg_dir,
NULL,
+ NULL,
+ NULL,
&filename,
&reread,
NULL,
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
index 8f9be772bb..23f4015609 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c
@@ -75,11 +75,6 @@ G_DEFINE_TYPE (SettingsPluginIfupdown, settings_plugin_ifupdown, NM_TYPE_SETTING
/*****************************************************************************/
-static SettingsPluginIfupdown *settings_plugin_ifupdown_get (void);
-NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfupdown, settings_plugin_ifupdown_get, SETTINGS_TYPE_PLUGIN_IFUPDOWN);
-
-/*****************************************************************************/
-
#define _NMLOG_PREFIX_NAME "ifupdown"
#define _NMLOG_DOMAIN LOGD_SETTINGS
#define _NMLOG(level, ...) \
@@ -339,5 +334,5 @@ settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *klass)
G_MODULE_EXPORT NMSettingsPlugin *
nm_settings_plugin_factory (void)
{
- return NM_SETTINGS_PLUGIN (g_object_ref (settings_plugin_ifupdown_get ()));
+ return g_object_new (SETTINGS_TYPE_PLUGIN_IFUPDOWN, NULL);
}
diff --git a/tools/create-exports-NetworkManager.sh b/tools/create-exports-NetworkManager.sh
index 052968999a..b089aba2fc 100755
--- a/tools/create-exports-NetworkManager.sh
+++ b/tools/create-exports-NetworkManager.sh
@@ -61,7 +61,7 @@ get_symbols_missing() {
./src/devices/*/${libs} \
./src/ppp/${libs} -name '*.so' 2>/dev/null); do
call_nm "$f" |
- sed -n 's/^\([U]\) \(\(nm_\|nmp_\|_nm\|NM\|_NM\|c_siphash_\).*\)$/\2/p'
+ sed -n 's/^\([U]\) \(\(nm_\|nmp_\|_nm\|NM\|_NM\|nmtst_\|c_siphash_\|c_list_\).*\)$/\2/p'
done) |
_sort |
grep -Fx -f <(get_symbols_explict) -v |