summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-08-31 19:20:53 +0200
committerThomas Haller <thaller@redhat.com>2022-08-31 19:22:27 +0200
commit424f09e43dfb37c117a5a8b85102648969bcddfe (patch)
tree772e6e4c1b0f940a33ff8c40ee83d5823306631c
parent98c3ac14803ca762f1f7b00b9e8fd5670cf34bab (diff)
parentef712733aab8dcfd542eb0fe8f17106a1bb3f976 (diff)
downloadNetworkManager-424f09e43dfb37c117a5a8b85102648969bcddfe.tar.gz
nmcli: merge branch 'th/nmcli-modify-uuid'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1349
-rw-r--r--NEWS3
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c12
-rw-r--r--src/libnm-glib-aux/nm-inet-utils.c2
-rw-r--r--src/libnm-glib-aux/nm-str-buf.h4
-rw-r--r--src/libnm-glib-aux/nm-uuid.c2
-rw-r--r--src/libnmc-setting/nm-meta-setting-desc.c377
-rw-r--r--src/libnmc-setting/nm-meta-setting-desc.h17
-rw-r--r--src/libnmc-setting/settings-docs.h.in2
-rw-r--r--src/nmcli/generate-docs-nm-settings-nmcli.xml.in2
-rw-r--r--src/nmcli/settings.c11
10 files changed, 266 insertions, 166 deletions
diff --git a/NEWS b/NEWS
index 1438a4e474..cd7fc03efd 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ subject to change and not guaranteed to be compatible with
the later release.
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
+* nmcli: allow changing "connection.uuid" and "connection.type"
+ in offline mode and setting the UUID when creating a connection.
+
=============================================
NetworkManager-1.40
Overview of changes since NetworkManager-1.38
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index cbce1c121d..55687179be 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -1848,6 +1848,18 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
* be generated by nm_utils_uuid_generate() or
* nm_uuid_generate_from_string_str().
**/
+ /* ---nmcli---
+ * property: uuid
+ * format: a valid RFC4122 universally unique identifier (UUID).
+ * description: The connection.uuid is the real identifier of a profile.
+ * It cannot change and it must be unique. It is therefore often best
+ * to refer to a profile by UUID, for example with `nmcli connection up uuid $UUID`.
+ *
+ * The UUID cannot be changed, except in offline mode. In that case,
+ * the special values "new", "generate" and "" are allowed to generate
+ * a new random UUID.
+ * ---end---
+ */
/* ---ifcfg-rh---
* property: uuid
* variable: UUID(+)
diff --git a/src/libnm-glib-aux/nm-inet-utils.c b/src/libnm-glib-aux/nm-inet-utils.c
index 2ede87baf9..7f710f3527 100644
--- a/src/libnm-glib-aux/nm-inet-utils.c
+++ b/src/libnm-glib-aux/nm-inet-utils.c
@@ -98,7 +98,7 @@ nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, in
g_return_val_if_fail(dst, FALSE);
g_return_val_if_fail(variant, FALSE);
- /* This function always expects IP addressea a byte arrays ("ay"). Note that
+ /* This function always expects IP addresses as byte arrays ("ay"). Note that
* several NetworkManager API uses "u" (32 bit unsigned intergers) for IPv4 addresses.
* So this function won't work in those cases.
*
diff --git a/src/libnm-glib-aux/nm-str-buf.h b/src/libnm-glib-aux/nm-str-buf.h
index 652bc96b25..8d68c1eee3 100644
--- a/src/libnm-glib-aux/nm-str-buf.h
+++ b/src/libnm-glib-aux/nm-str-buf.h
@@ -78,14 +78,14 @@ NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem)
? (size) \
: 0, \
FALSE, \
- (do_bzero_mem));
+ (do_bzero_mem))
#define NM_STR_BUF_INIT_ARR(arr, do_bzero_mem) \
NM_STR_BUF_INIT_FULL((arr), \
0, \
NM_STATIC_ASSERT_EXPR_1(sizeof(arr) > sizeof(char *)) ? sizeof(arr) : 0, \
FALSE, \
- (do_bzero_mem));
+ (do_bzero_mem))
void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact);
diff --git a/src/libnm-glib-aux/nm-uuid.c b/src/libnm-glib-aux/nm-uuid.c
index 53e8b78cd7..817279db6b 100644
--- a/src/libnm-glib-aux/nm-uuid.c
+++ b/src/libnm-glib-aux/nm-uuid.c
@@ -425,7 +425,7 @@ nm_uuid_generate_from_strings(const char *string1, ...)
return nm_uuid_generate_from_string_str(NULL, 0, NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1);
{
- nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
+ nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE);
va_list args;
const char *s;
diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c
index e9ae2b9316..2e471d66a5 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.c
+++ b/src/libnmc-setting/nm-meta-setting-desc.c
@@ -15,6 +15,7 @@
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "libnm-glib-aux/nm-enum-utils.h"
#include "libnm-glib-aux/nm-secret-utils.h"
+#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
#include "libnm-core-aux-extern/nm-libnm-core-aux.h"
@@ -262,23 +263,21 @@ _parse_ip_address(int family, const char *address, GError **error)
if (plen) {
*plen++ = '\0';
if ((prefix = _nm_utils_ascii_str_to_int64(plen, 10, 0, MAX_PREFIX, -1)) == -1) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("invalid prefix '%s'; <0-%d> allowed"),
- plen,
- MAX_PREFIX);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("invalid prefix '%s'; <0-%d> allowed"),
+ plen,
+ MAX_PREFIX);
return NULL;
}
}
addr = nm_ip_address_new(family, ip_str, prefix, &local);
if (!addr) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("invalid IP address: %s"),
- local->message);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("invalid IP address: %s"),
+ local->message);
g_clear_error(&local);
}
return addr;
@@ -312,7 +311,11 @@ _parse_ip_route(int family, const char *str, GError **error)
str_clean = nm_strstrip_avoid_copy_a(300, str, &str_clean_free);
routev = nm_strsplit_set(str_clean, " \t");
if (!routev) {
- g_set_error(error, 1, 0, "'%s' is not valid. %s", str, ROUTE_SYNTAX);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ "'%s' is not valid. %s",
+ str,
+ ROUTE_SYNTAX);
return NULL;
}
@@ -328,12 +331,11 @@ _parse_ip_route(int family, const char *str, GError **error)
prefix = MAX_PREFIX;
if (plen) {
if ((prefix = _nm_utils_ascii_str_to_int64(plen, 10, 0, MAX_PREFIX, -1)) == -1) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("invalid prefix '%s'; <0-%d> allowed"),
- plen,
- MAX_PREFIX);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("invalid prefix '%s'; <0-%d> allowed"),
+ plen,
+ MAX_PREFIX);
return NULL;
}
}
@@ -343,18 +345,20 @@ _parse_ip_route(int family, const char *str, GError **error)
if (nm_inet_is_valid(family, routev[i])) {
if (metric != -1 || attrs) {
- g_set_error(error, 1, 0, _("the next hop ('%s') must be first"), routev[i]);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("the next hop ('%s') must be first"),
+ routev[i]);
return NULL;
}
next_hop = routev[i];
} else if ((tmp64 = _nm_utils_ascii_str_to_int64(routev[i], 10, 0, G_MAXUINT32, -1))
!= -1) {
if (attrs) {
- g_set_error(error,
- 1,
- 0,
- _("the metric ('%s') must be before attributes"),
- routev[i]);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("the metric ('%s') must be before attributes"),
+ routev[i]);
return NULL;
}
metric = tmp64;
@@ -397,14 +401,18 @@ _parse_ip_route(int family, const char *str, GError **error)
g_hash_table_iter_steal(&iter);
}
} else {
- g_set_error(error, 1, 0, "%s", ROUTE_SYNTAX);
+ nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "%s", ROUTE_SYNTAX);
return NULL;
}
}
route = nm_ip_route_new(family, dest, prefix, next_hop, metric, &local);
if (!route) {
- g_set_error(error, 1, 0, _("invalid route: %s. %s"), local->message, ROUTE_SYNTAX);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("invalid route: %s. %s"),
+ local->message,
+ ROUTE_SYNTAX);
g_clear_error(&local);
return NULL;
}
@@ -469,20 +477,18 @@ nmc_proxy_check_script(const char *script, char **out_script, GError **error)
if (!g_file_get_contents(script, &contents, &c_len, NULL)) {
if (desired_type == _PAC_SCRIPT_TYPE_FILE) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("cannot read pac-script from file '%s'"),
- script);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("cannot read pac-script from file '%s'"),
+ script);
return FALSE;
}
} else {
if (c_len != strlen(contents)) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("file '%s' contains non-valid utf-8"),
- script);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("file '%s' contains non-valid utf-8"),
+ script);
return FALSE;
}
filename = script;
@@ -492,16 +498,12 @@ nmc_proxy_check_script(const char *script, char **out_script, GError **error)
if (!strstr(script, "FindProxyForURL") || !g_utf8_validate(script, -1, NULL)) {
if (filename) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("'%s' does not contain a valid PAC Script"),
- filename);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("'%s' does not contain a valid PAC Script"),
+ filename);
} else {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("Not a valid PAC Script"));
+ nm_utils_error_set(error, NM_UTILS_ERROR_INVALID_ARGUMENT, _("Not a valid PAC Script"));
}
return FALSE;
}
@@ -551,20 +553,18 @@ nmc_team_check_config(const char *config, char **out_config, GError **error)
if (!g_file_get_contents(config, &contents, &c_len, NULL)) {
if (desired_type == _TEAM_CONFIG_TYPE_FILE) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("cannot read team config from file '%s'"),
- config);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("cannot read team config from file '%s'"),
+ config);
return FALSE;
}
} else {
if (c_len != strlen(contents)) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("team config file '%s' contains non-valid utf-8"),
- config);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("team config file '%s' contains non-valid utf-8"),
+ config);
return FALSE;
}
config = config_clone = g_steal_pointer(&contents);
@@ -1411,29 +1411,27 @@ _set_fcn_gobject_int(ARGS_SET_FCN)
if ((errsv = errno) != 0) {
if (errsv == ERANGE) {
if (is_uint64) {
- g_set_error(
+ nm_utils_error_set(
error,
- NM_UTILS_ERROR,
NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is out of range [%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT "]"),
value,
min.u64,
max.u64);
} else {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("'%s' is out of range [%" G_GINT64_FORMAT ", %" G_GINT64_FORMAT "]"),
- value,
- min.i64,
- max.i64);
+ nm_utils_error_set(
+ error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("'%s' is out of range [%" G_GINT64_FORMAT ", %" G_GINT64_FORMAT "]"),
+ value,
+ min.i64,
+ max.i64);
}
} else {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("'%s' is not a valid number"),
- value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("'%s' is not a valid number"),
+ value);
}
return FALSE;
}
@@ -1486,12 +1484,11 @@ _set_fcn_gobject_mtu(ARGS_SET_FCN)
v = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT32, -1);
if (v < 0) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("'%s' is out of range [0, %u]"),
- value,
- (unsigned) G_MAXUINT32);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("'%s' is out of range [0, %u]"),
+ value,
+ (unsigned) G_MAXUINT32);
return FALSE;
}
@@ -1534,7 +1531,10 @@ _set_fcn_gobject_mac(ARGS_SET_FCN)
}
if (!valid) {
- g_set_error(error, 1, 0, _("'%s' is not a valid Ethernet MAC"), value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not a valid Ethernet MAC"),
+ value);
return FALSE;
}
@@ -1656,19 +1656,17 @@ fail:
valid_all = nm_utils_enum_get_values(gtype, min, max);
valid_str = g_strjoinv(",", (char **) valid_all);
if (is_flags) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("invalid option '%s', use a combination of [%s]"),
- value,
- valid_str);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("invalid option '%s', use a combination of [%s]"),
+ value,
+ valid_str);
} else {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("invalid option '%s', use one of [%s]"),
- value,
- valid_str);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("invalid option '%s', use one of [%s]"),
+ value,
+ valid_str);
}
}
return FALSE;
@@ -2159,12 +2157,11 @@ validate_flags(NMSetting *setting, const char *prop, guint val, GError **error)
flag_values = flag_values_to_string(pspec_flags->flags_class->values,
pspec_flags->flags_class->n_values);
- g_set_error(error,
- 1,
- 0,
- _("'%u' flags are not valid; use combination of %s"),
- val,
- flag_values);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%u' flags are not valid; use combination of %s"),
+ val,
+ flag_values);
success = FALSE;
}
g_value_unset(&value);
@@ -2180,7 +2177,10 @@ _set_fcn_gobject_flags(ARGS_SET_FCN)
return _gobject_property_reset_default(setting, property_info->property_name);
if (!nmc_string_to_uint(value, TRUE, 0, G_MAXUINT, &val_int)) {
- g_set_error(error, 1, 0, _("'%s' is not a valid number (or out of range)"), value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not a valid number (or out of range)"),
+ value);
return FALSE;
}
@@ -2201,7 +2201,7 @@ _set_fcn_gobject_ssid(ARGS_SET_FCN)
return _gobject_property_reset_default(setting, property_info->property_name);
if (strlen(value) > 32) {
- g_set_error(error, 1, 0, _("'%s' is not valid"), value);
+ nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, _("'%s' is not valid"), value);
return FALSE;
}
@@ -2326,7 +2326,10 @@ _set_fcn_gobject_bytes(ARGS_SET_FCN)
v = _nm_utils_ascii_str_to_int64(*iter, 16, 0, 255, -1);
if (v == -1) {
- g_set_error(error, 1, 0, _("'%s' is not a valid hex character"), *iter);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not a valid hex character"),
+ *iter);
g_byte_array_free(array, TRUE);
return FALSE;
}
@@ -2631,30 +2634,67 @@ _get_fcn_connection_permissions(ARGS_GET_FCN)
}
static gboolean
-_set_fcn_connection_type(ARGS_SET_FCN)
+_set_fcn_connection_uuid(ARGS_SET_FCN)
{
- gs_free char *uuid = NULL;
-
- if (nm_setting_connection_get_uuid(NM_SETTING_CONNECTION(setting))) {
- /* Don't allow setting type unless the connection is brand new.
- * Just because it's a bad idea and the user wouldn't probably want that.
- * No technical reason, really.
- * Also, using uuid to see if the connection is brand new is a bit
- * hacky: we can not see if the type is already set, because
- * nmc_setting_set_property() is called only after the property
- * we're setting (type) has been removed. */
- g_set_error(error, 1, 0, _("Can not change the connection type"));
+ const char *uuid;
+
+ uuid = nm_setting_connection_get_uuid(NM_SETTING_CONNECTION(setting));
+
+ if (!uuid) {
+ /* No UUID yet, we are about to create a new profile. We can set the UUID. */
+ } else if (NM_FLAGS_HAS(nm_meta_environment_get_env_flags(environment, environment_user_data),
+ NM_META_ENV_FLAGS_OFFLINE)) {
+ /* In offline mode, we can change it. */
+ } else if (nm_uuid_is_valid_nmlegacy(value) && nm_streq(uuid, value)) {
+ /* Setting the same value does not actually trigger an error. */
+ } else {
+ /* The UUID is the unchanging ID of a profile. It cannot change, unless
+ * we are in offline mode (in which case, it can be useful to do just that). */
+ nm_utils_error_set(error, NM_UTILS_ERROR_INVALID_ARGUMENT, "the property can't be changed");
return FALSE;
}
+ if (NM_IN_STRSET(value, NULL, "", "new", "generate")) {
+ /* Special keywords are used for generating a new UUID. */
+ value = nm_uuid_generate_random_str_a();
+ }
+
+ g_object_set(G_OBJECT(setting), NM_SETTING_CONNECTION_UUID, value, NULL);
+ return TRUE;
+}
+
+static gboolean
+_set_fcn_connection_type(ARGS_SET_FCN)
+{
+ const char *connection_type;
+
+ connection_type = nm_setting_connection_get_connection_type(NM_SETTING_CONNECTION(setting));
+
+ if (connection_type) {
+ if (nm_streq0(connection_type, value)) {
+ /* No change. Setting the same again is fine. */
+ return TRUE;
+ }
+
+ /* There is no technical reason that a profile couldn't change its type.
+ * NetworkManager allows that just fine.
+ *
+ * However, it seems an unusual thing to do, so only allow that in
+ * offline mode. */
+ if (!NM_FLAGS_HAS(nm_meta_environment_get_env_flags(environment, environment_user_data),
+ NM_META_ENV_FLAGS_OFFLINE)) {
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("Can not change the connection type"));
+ return FALSE;
+ }
+ }
+
if (_SET_FCN_DO_RESET_DEFAULT(property_info, modifier, value)) {
g_object_set(G_OBJECT(setting), property_info->property_name, NULL, NULL);
return TRUE;
}
- uuid = nm_utils_uuid_generate();
- g_object_set(G_OBJECT(setting), NM_SETTING_CONNECTION_UUID, uuid, NULL);
-
g_object_set(G_OBJECT(setting), property_info->property_name, value, NULL);
return TRUE;
}
@@ -2994,7 +3034,10 @@ _set_fcn_dcb_flags(ARGS_SET_FCN)
|| g_ascii_strcasecmp(*iter, "disabled") == 0 || t == 0) {
/* pass */
} else {
- g_set_error(error, 1, 0, _("'%s' is not a valid DCB flag"), *iter);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not a valid DCB flag"),
+ *iter);
return FALSE;
}
}
@@ -3034,20 +3077,18 @@ dcb_parse_uint_array(const char *val,
/* If number is greater than 'max' it must equal 'other' */
if (num == -1 || (other && (num > max) && (num != other))) {
if (other) {
- g_set_error(error,
- 1,
- 0,
- _("'%s' not a number between 0 and %u (inclusive) or %u"),
- *iter,
- max,
- other);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' not a number between 0 and %u (inclusive) or %u"),
+ *iter,
+ max,
+ other);
} else {
- g_set_error(error,
- 1,
- 0,
- _("'%s' not a number between 0 and %u (inclusive)"),
- *iter,
- max);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' not a number between 0 and %u (inclusive)"),
+ *iter,
+ max);
}
return FALSE;
}
@@ -3233,7 +3274,10 @@ _set_fcn_infiniband_p_key(ARGS_SET_FCN)
else {
p_key = _nm_utils_ascii_str_to_int64(value, 0, -1, G_MAXUINT16, -2);
if (p_key == -2) {
- g_set_error(error, 1, 0, _("'%s' is not a valid IBoIP P_Key"), value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not a valid IBoIP P_Key"),
+ value);
return FALSE;
}
}
@@ -3542,11 +3586,10 @@ _set_fcn_ip_config_gateway(ARGS_SET_FCN)
value = nm_strstrip_avoid_copy_a(300, value, &value_to_free);
if (!nm_inet_is_valid(addr_family, value)) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("invalid gateway address '%s'"),
- value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("invalid gateway address '%s'"),
+ value);
return FALSE;
}
@@ -3695,7 +3738,10 @@ _set_fcn_olpc_mesh_channel(ARGS_SET_FCN)
return _gobject_property_reset_default(setting, property_info->property_name);
if (!nmc_string_to_uint(value, TRUE, 1, 13, &chan_int)) {
- g_set_error(error, 1, 0, _("'%s' is not a valid channel; use <1-13>"), value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not a valid channel; use <1-13>"),
+ value);
return FALSE;
}
g_object_set(setting, property_info->property_name, chan_int, NULL);
@@ -4026,7 +4072,10 @@ _set_fcn_vlan_xgress_priority_map(ARGS_SET_FCN)
NULL,
NULL,
NULL)) {
- g_set_error(error, 1, 0, _("invalid priority map '%s'"), prio_map[i]);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("invalid priority map '%s'"),
+ prio_map[i]);
return FALSE;
}
}
@@ -4116,7 +4165,10 @@ _set_fcn_wired_s390_subchannels(ARGS_SET_FCN)
strv = nm_strsplit_set(value, " ,\t");
len = NM_PTRARRAY_LEN(strv);
if (len != 2 && len != 3) {
- g_set_error(error, 1, 0, _("'%s' is not valid; 2 or 3 strings should be provided"), value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' is not valid; 2 or 3 strings should be provided"),
+ value);
return FALSE;
}
@@ -4188,13 +4240,16 @@ _set_fcn_wireless_channel(ARGS_SET_FCN)
return _gobject_property_reset_default(setting, property_info->property_name);
if (!nmc_string_to_uint(value, FALSE, 0, 0, &chan_int)) {
- g_set_error(error, 1, 0, _("'%s' is not a valid channel"), value);
+ nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, _("'%s' is not a valid channel"), value);
return FALSE;
}
if (!nm_utils_wifi_is_channel_valid(chan_int, "a")
&& !nm_utils_wifi_is_channel_valid(chan_int, "bg")) {
- g_set_error(error, 1, 0, _("'%ld' is not a valid channel"), chan_int);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%ld' is not a valid channel"),
+ chan_int);
return FALSE;
}
@@ -4262,7 +4317,7 @@ _set_fcn_wireless_wep_key(ARGS_SET_FCN)
guessed_type = NM_WEP_KEY_TYPE_PASSPHRASE;
if (guessed_type == NM_WEP_KEY_TYPE_UNKNOWN) {
- g_set_error(error, 1, 0, _("'%s' is not valid"), value);
+ nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, _("'%s' is not valid"), value);
return FALSE;
}
@@ -4270,15 +4325,15 @@ _set_fcn_wireless_wep_key(ARGS_SET_FCN)
if (nm_utils_wep_key_valid(value, type))
guessed_type = type;
else {
- g_set_error(error,
- 1,
- 0,
- _("'%s' not compatible with %s '%s', please change the key or set the "
- "right %s first."),
- value,
- NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
- wep_key_type_to_string(type),
- NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE);
+ nm_utils_error_set(
+ error,
+ NM_UTILS_ERROR_UNKNOWN,
+ _("'%s' not compatible with %s '%s', please change the key or set the "
+ "right %s first."),
+ value,
+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+ wep_key_type_to_string(type),
+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE);
return FALSE;
}
}
@@ -4387,13 +4442,13 @@ _set_fcn_ethtool(ARGS_SET_FCN)
if (nm_ethtool_id_is_coalesce(ethtool_id) || nm_ethtool_id_is_ring(ethtool_id)) {
i64 = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT32, -1);
if (i64 == -1) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("'%s' is out of range [%" G_GUINT32_FORMAT ", %" G_GUINT32_FORMAT "]"),
- value,
- 0,
- G_MAXUINT32);
+ nm_utils_error_set(
+ error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("'%s' is out of range [%" G_GUINT32_FORMAT ", %" G_GUINT32_FORMAT "]"),
+ value,
+ 0,
+ G_MAXUINT32);
return FALSE;
}
@@ -4407,11 +4462,10 @@ _set_fcn_ethtool(ARGS_SET_FCN)
NMC_STRING_TO_TERNARY_FLAGS_IGNORE_FOR_DEFAULT,
&t,
NULL)) {
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_INVALID_ARGUMENT,
- _("'%s' is not valid; use 'on', 'off', or 'ignore'"),
- value);
+ nm_utils_error_set(error,
+ NM_UTILS_ERROR_INVALID_ARGUMENT,
+ _("'%s' is not valid; use 'on', 'off', or 'ignore'"),
+ value);
return FALSE;
}
if (t == NM_TERNARY_DEFAULT)
@@ -5379,7 +5433,10 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
.property_type = &_pt_gobject_string,
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_UUID,
- .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject ),
+ .property_type = DEFINE_PROPERTY_TYPE (
+ .get_fcn = _get_fcn_gobject,
+ .set_fcn = _set_fcn_connection_uuid,
+ ),
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_STABLE_ID,
.property_type = &_pt_gobject_string,
diff --git a/src/libnmc-setting/nm-meta-setting-desc.h b/src/libnmc-setting/nm-meta-setting-desc.h
index ca04457131..8e3383cc56 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.h
+++ b/src/libnmc-setting/nm-meta-setting-desc.h
@@ -486,6 +486,11 @@ typedef enum {
NM_META_ENV_WARN_LEVEL_WARN,
} NMMetaEnvWarnLevel;
+typedef enum {
+ NM_META_ENV_FLAGS_NONE = 0,
+ NM_META_ENV_FLAGS_OFFLINE = 0x1,
+} NMMetaEnvFlags;
+
/* the settings-meta data is supposed to be independent of an actual client
* implementation. Hence, there is a need for hooks to the meta-data.
* The meta-data handlers may call back to the environment with certain
@@ -506,8 +511,20 @@ struct _NMMetaEnvironment {
struct _NMRemoteConnection *const *(*get_nm_connections)(const NMMetaEnvironment *environment,
gpointer environment_user_data,
guint *out_len);
+
+ NMMetaEnvFlags (*get_env_flags)(const NMMetaEnvironment *environment,
+ gpointer environment_user_data);
};
+static inline NMMetaEnvFlags
+nm_meta_environment_get_env_flags(const NMMetaEnvironment *environment,
+ gpointer environment_user_data)
+{
+ if (environment && environment->get_env_flags)
+ return environment->get_env_flags(environment, environment_user_data);
+ return NM_META_ENV_FLAGS_NONE;
+}
+
/*****************************************************************************/
/* NMSettingBond is special in that it has nested properties.
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index 1ed2f13419..2aef829a46 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -24,7 +24,7 @@
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds to the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("The connection.uuid is the real identifier of a profile. It cannot change and it must be unique. It is therefore often best to refer to a profile by UUID, for example with `nmcli connection up uuid $UUID`. The UUID cannot be changed, except in offline mode. In that case, the special values \"new\", \"generate\" and \"\" are allowed to generate a new random UUID.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY N_("Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.")
#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection. Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.")
diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
index 371081b0e0..b6d275c69d 100644
--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
+++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in
@@ -369,7 +369,7 @@
alias="con-name"
description="A human readable unique identifier for the connection, like &quot;Work Wi-Fi&quot; or &quot;T-Mobile 3G&quot;." />
<property name="uuid"
- description="A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the &quot;id&quot; property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or &quot;type&quot; property changes. The UUID must be in the format &quot;2815492f-7e56-435e-b2e9-246bd7cdc664&quot; (ie, contains only hexadecimal characters and &quot;-&quot;)." />
+ description="The connection.uuid is the real identifier of a profile. It cannot change and it must be unique. It is therefore often best to refer to a profile by UUID, for example with `nmcli connection up uuid $UUID`. The UUID cannot be changed, except in offline mode. In that case, the special values &quot;new&quot;, &quot;generate&quot; and &quot;&quot; are allowed to generate a new random UUID." />
<property name="stable-id"
description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device&apos;s name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The &apos;$&apos; character is treated special to perform dynamic substitutions at runtime. Currently, supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${MAC}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that &quot;${DEVICE}&quot; corresponds to the interface name of the device and &quot;${MAC}&quot; is the permanent MAC address of the device. Any unrecognized patterns following &apos;$&apos; are treated verbatim, however are reserved for future use. You are thus advised to avoid &apos;$&apos; or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to &quot;${CONNECTION}&quot; and uses a unique, fixed ID for the connection." />
<property name="type"
diff --git a/src/nmcli/settings.c b/src/nmcli/settings.c
index c80d0c7c5b..d6c36ac023 100644
--- a/src/nmcli/settings.c
+++ b/src/nmcli/settings.c
@@ -488,12 +488,23 @@ _env_get_nm_connections(const NMMetaEnvironment *environment,
return (NMRemoteConnection *const *) values->pdata;
}
+static NMMetaEnvFlags
+_env_get_env_flags(const NMMetaEnvironment *environment, gpointer environment_user_data)
+{
+ NmCli *nmc = environment_user_data;
+
+ nm_assert(nmc);
+
+ return (nmc->offline ? NM_META_ENV_FLAGS_OFFLINE : NM_META_ENV_FLAGS_NONE);
+}
+
/*****************************************************************************/
const NMMetaEnvironment *const nmc_meta_environment = &((NMMetaEnvironment){
.warn_fcn = _env_warn_fcn_handle,
.get_nm_devices = _env_get_nm_devices,
.get_nm_connections = _env_get_nm_connections,
+ .get_env_flags = _env_get_env_flags,
});
static char *