[PATCH 1/2] settings: add match for proc cmdline



Add a new "kernel-command-line" match option to nm-settings. It allows
to disable a network connection configuration if a pattern is found or
is not found in /proc/cmdline.
---
 clients/common/nm-meta-setting-desc.c |  45 +++++++
 clients/common/settings-docs.h.in     |   1 +
 libnm-core/nm-setting-match.c         | 174 ++++++++++++++++++++++++++
 libnm-core/nm-setting-match.h         |  19 +++
 libnm/libnm.ver                       |   7 ++
 src/devices/nm-device.c               |  16 ++-
 6 files changed, 261 insertions(+), 1 deletion(-)

diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index cd04e31d4..373841484 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -3440,6 +3440,35 @@ _get_fcn_match_interface_name (ARGS_GET_FCN)
        RETURN_STR_TO_FREE (g_string_free (str, FALSE));
 }
 
+static gconstpointer
+_get_fcn_match_kernel_command_line (ARGS_GET_FCN)
+{
+       NMSettingMatch *s_match = NM_SETTING_MATCH (setting);
+       GString *str = NULL;
+       guint i, num;
+
+       RETURN_UNSUPPORTED_GET_TYPE ();
+
+       num = nm_setting_match_get_num_kernel_command_lines (s_match);
+       for (i = 0; i < num; i++) {
+               const char *name;
+
+               name = nm_setting_match_get_kernel_command_line (s_match, i);
+               if (!name || !name[0])
+                       continue;
+               if (!str)
+                       str = g_string_new ("");
+               else
+                       g_string_append_c (str, ESCAPED_TOKENS_WITH_SPACES_DELIMTER);
+               nm_utils_escaped_tokens_escape_gstr (name, ESCAPED_TOKENS_WITH_SPACES_DELIMTERS, str);
+       }
+
+       NM_SET_OUT (out_is_default, num == 0);
+       if (!str)
+               return NULL;
+       RETURN_STR_TO_FREE (g_string_free (str, FALSE));
+}
+
 static gconstpointer
 _get_fcn_olpc_mesh_ssid (ARGS_GET_FCN)
 {
@@ -6107,6 +6136,22 @@ static const NMMetaPropertyInfo *const property_infos_MATCH[] = {
                ),
            ),
        ),
+       PROPERTY_INFO_WITH_DESC (NM_SETTING_MATCH_KERNEL_COMMAND_LINE,
+           .property_type = DEFINE_PROPERTY_TYPE (
+               .get_fcn =                  _get_fcn_match_kernel_command_line,
+               .set_fcn =                  _set_fcn_multilist,
+               .set_supports_remove =      TRUE,
+           ),
+           .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
+               PROPERTY_TYP_DATA_SUBTYPE (multilist,
+                   .get_num_fcn_u   =      MULTILIST_GET_NUM_FCN_U       (NMSettingMatch, 
nm_setting_match_get_num_kernel_command_lines),
+                   .add2_fcn =             MULTILIST_ADD2_FCN            (NMSettingMatch, 
nm_setting_match_add_kernel_command_line),
+                   .remove_by_idx_fcn_s =  MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingMatch, 
nm_setting_match_remove_kernel_command_line),
+                   .remove_by_value_fcn =  MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingMatch, 
nm_setting_match_remove_kernel_command_line_by_value),
+                   .strsplit_with_spaces = TRUE,
+               ),
+           ),
+       ),
        NULL
 };
 
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 69856394c..37f680133 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -263,6 +263,7 @@
 #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous 
mode.")
 #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.")
 #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is 
a shell wildcard pattern.  When an element is prefixed with exclamation mark (!) the condition is inverted. A 
candidate interface name is considered matching when both these conditions are satisfied: (a) any of the 
elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with 
'!' match.")
+#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of strings searched in the kernel 
command line arguments. When an element is prefixed with exclamation mark (!) the condition is inverted.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", 
\"netdev\" or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", 
\"standalone\" or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.")
diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c
index 2fbd0716b..a56539bba 100644
--- a/libnm-core/nm-setting-match.c
+++ b/libnm-core/nm-setting-match.c
@@ -20,6 +20,7 @@
 
 NM_GOBJECT_PROPERTIES_DEFINE (NMSettingMatch,
        PROP_INTERFACE_NAME,
+       PROP_KERNEL_COMMAND_LINE,
 );
 
 /**
@@ -32,6 +33,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingMatch,
 struct _NMSettingMatch {
        NMSetting parent;
        GPtrArray *interface_name;
+       GPtrArray *kernel_command_line;
 };
 
 struct _NMSettingMatchClass {
@@ -190,6 +192,154 @@ nm_setting_match_get_interface_names (NMSettingMatch *setting, guint *length)
 
 /*****************************************************************************/
 
+/**
+ * nm_setting_match_get_num_kernel_command_lines:
+ * @setting: the #NMSettingMatch
+ *
+ * Returns: the number of configured kernel command line arguments
+ *
+ * Since: 1.24
+ **/
+guint
+nm_setting_match_get_num_kernel_command_lines (NMSettingMatch *setting)
+{
+       g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), 0);
+
+       return setting->kernel_command_line->len;
+}
+
+/**
+ * nm_setting_match_get_kernel_command_line:
+ * @setting: the #NMSettingMatch
+ * @idx: index number of the kernel command line argument to return
+ *
+ * Returns: the kernel command line argument at index @idx
+ *
+ * Since: 1.24
+ **/
+const char *
+nm_setting_match_get_kernel_command_line (NMSettingMatch *setting, int idx)
+{
+       g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), NULL);
+
+       g_return_val_if_fail (idx >= 0 && idx < setting->kernel_command_line->len, NULL);
+
+       return setting->kernel_command_line->pdata[idx];
+}
+
+/**
+ * nm_setting_match_add_kernel_command_line:
+ * @setting: the #NMSettingMatch
+ * @kernel_command_line: the kernel command line argument to add
+ *
+ * Adds a new kernel command line argument to the setting.
+ *
+ * Since: 1.24
+ **/
+void
+nm_setting_match_add_kernel_command_line (NMSettingMatch *setting,
+                                     const char *kernel_command_line)
+{
+       g_return_if_fail (NM_IS_SETTING_MATCH (setting));
+       g_return_if_fail (kernel_command_line != NULL);
+       g_return_if_fail (kernel_command_line[0] != '\0');
+
+       g_ptr_array_add (setting->kernel_command_line, g_strdup (kernel_command_line));
+       _notify (setting, PROP_KERNEL_COMMAND_LINE);
+}
+
+/**
+ * nm_setting_match_remove_kernel_command_line:
+ * @setting: the #NMSettingMatch
+ * @idx: index number of the kernel command line argument
+ *
+ * Removes the ikernel command line argument at index @idx.
+ *
+ * Since: 1.24
+ **/
+void
+nm_setting_match_remove_kernel_command_line (NMSettingMatch *setting, int idx)
+{
+       g_return_if_fail (NM_IS_SETTING_MATCH (setting));
+
+       g_return_if_fail (idx >= 0 && idx < setting->kernel_command_line->len);
+
+       g_ptr_array_remove_index (setting->kernel_command_line, idx);
+       _notify (setting, PROP_KERNEL_COMMAND_LINE);
+}
+
+/**
+ * nm_setting_match_remove_kernel_command_line_by_value:
+ * @setting: the #NMSettingMatch
+ * @kernel_command_line: the kernel command line argument name to remove
+ *
+ * Removes @kernel_command_line.
+ *
+ * Returns: %TRUE if the kernel command line argument was found and removed; %FALSE if it was not.
+ *
+ * Since: 1.24
+ **/
+gboolean
+nm_setting_match_remove_kernel_command_line_by_value (NMSettingMatch *setting,
+                                                 const char *kernel_command_line)
+{
+       guint i;
+
+       g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), FALSE);
+       g_return_val_if_fail (kernel_command_line != NULL, FALSE);
+       g_return_val_if_fail (kernel_command_line[0] != '\0', FALSE);
+
+       for (i = 0; i < setting->kernel_command_line->len; i++) {
+               if (nm_streq (kernel_command_line, setting->kernel_command_line->pdata[i])) {
+                       g_ptr_array_remove_index (setting->kernel_command_line, i);
+                       _notify (setting, PROP_KERNEL_COMMAND_LINE);
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+/**
+ * nm_setting_match_clear_kernel_command_lines:
+ * @setting: the #NMSettingMatch
+ *
+ * Removes all configured kernel command line arguments.
+ *
+ * Since: 1.24
+ **/
+void
+nm_setting_match_clear_kernel_command_lines (NMSettingMatch *setting)
+{
+       g_return_if_fail (NM_IS_SETTING_MATCH (setting));
+
+       if (setting->kernel_command_line->len != 0) {
+               g_ptr_array_set_size (setting->kernel_command_line, 0);
+               _notify (setting, PROP_KERNEL_COMMAND_LINE);
+       }
+}
+
+/**
+ * nm_setting_match_get_kernel_command_lines:
+ * @setting: the #NMSettingMatch
+ *
+ * Returns all the interface names.
+ *
+ * Returns: (transfer none): the configured interface names.
+ *
+ * Since: 1.24
+ **/
+const char *const *
+nm_setting_match_get_kernel_command_lines (NMSettingMatch *setting, guint *length)
+{
+       g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), NULL);
+       g_return_val_if_fail (length, NULL);
+
+       NM_SET_OUT (length, setting->kernel_command_line->len);
+       return (const char *const *) setting->kernel_command_line->pdata;
+}
+
+/*****************************************************************************/
+
 static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
@@ -200,6 +350,9 @@ get_property (GObject *object, guint prop_id,
        case PROP_INTERFACE_NAME:
                g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (self->interface_name));
                break;
+       case PROP_KERNEL_COMMAND_LINE:
+               g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (self->kernel_command_line));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -217,6 +370,10 @@ set_property (GObject *object, guint prop_id,
                g_ptr_array_unref (self->interface_name);
                self->interface_name = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value));
                break;
+       case PROP_KERNEL_COMMAND_LINE:
+               g_ptr_array_unref (self->kernel_command_line);
+               self->kernel_command_line = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -229,6 +386,7 @@ static void
 nm_setting_match_init (NMSettingMatch *setting)
 {
        setting->interface_name = g_ptr_array_new_with_free_func (g_free);
+       setting->kernel_command_line = g_ptr_array_new_with_free_func (g_free);
 }
 
 /**
@@ -252,6 +410,7 @@ finalize (GObject *object)
        NMSettingMatch *self = NM_SETTING_MATCH (object);
 
        g_ptr_array_unref (self->interface_name);
+       g_ptr_array_unref (self->kernel_command_line);
 
        G_OBJECT_CLASS (nm_setting_match_parent_class)->finalize (object);
 }
@@ -287,6 +446,21 @@ nm_setting_match_class_init (NMSettingMatchClass *klass)
                                G_PARAM_READWRITE |
                                G_PARAM_STATIC_STRINGS);
 
+       /**
+        * NMSettingMatch:kernel-command-line
+        *
+        * A list of strings searched in the kernel command line arguments. When an
+     * element is prefixed with exclamation mark (!) the condition is inverted.
+        *
+        * Since: 1.24
+        **/
+       obj_properties[PROP_KERNEL_COMMAND_LINE] =
+           g_param_spec_boxed (NM_SETTING_MATCH_KERNEL_COMMAND_LINE, "", "",
+                               G_TYPE_STRV,
+                               NM_SETTING_PARAM_FUZZY_IGNORE |
+                               G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
+
        g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
        _nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_MATCH);
diff --git a/libnm-core/nm-setting-match.h b/libnm-core/nm-setting-match.h
index e15911adb..f9b493471 100644
--- a/libnm-core/nm-setting-match.h
+++ b/libnm-core/nm-setting-match.h
@@ -24,6 +24,7 @@ G_BEGIN_DECLS
 #define NM_SETTING_MATCH_SETTING_NAME      "match"
 
 #define NM_SETTING_MATCH_INTERFACE_NAME    "interface-name"
+#define NM_SETTING_MATCH_KERNEL_COMMAND_LINE    "kernel-command-line"
 
 typedef struct _NMSettingMatchClass NMSettingMatchClass;
 
@@ -49,6 +50,24 @@ NM_AVAILABLE_IN_1_14
 void nm_setting_match_clear_interface_names (NMSettingMatch *setting);
 NM_AVAILABLE_IN_1_14
 const char *const *nm_setting_match_get_interface_names (NMSettingMatch *setting, guint *length);
+
+
+NM_AVAILABLE_IN_1_24
+guint nm_setting_match_get_num_kernel_command_lines (NMSettingMatch *setting);
+NM_AVAILABLE_IN_1_24
+const char *nm_setting_match_get_kernel_command_line (NMSettingMatch *setting, int idx);
+NM_AVAILABLE_IN_1_24
+void nm_setting_match_remove_kernel_command_line (NMSettingMatch *setting, int idx);
+NM_AVAILABLE_IN_1_24
+gboolean nm_setting_match_remove_kernel_command_line_by_value (NMSettingMatch *setting,
+                                                          const char *kernel_command_line);
+NM_AVAILABLE_IN_1_24
+void nm_setting_match_add_kernel_command_line (NMSettingMatch *setting,
+                                          const char *kernel_command_line);
+NM_AVAILABLE_IN_1_24
+void nm_setting_match_clear_kernel_command_lines (NMSettingMatch *setting);
+NM_AVAILABLE_IN_1_24
+const char *const *nm_setting_match_get_kernel_command_lines (NMSettingMatch *setting, guint *length);
 G_END_DECLS
 
 #endif /* NM_SETTING_MATCH_H */
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 9229a1fc7..5d7873f4d 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1411,6 +1411,13 @@ global:
        nm_setting_match_get_type;
        nm_setting_match_remove_interface_name;
        nm_setting_match_remove_interface_name_by_value;
+       nm_setting_match_add_kernel_command_line;
+       nm_setting_match_clear_kernel_command_lines;
+       nm_setting_match_get_kernel_command_line;
+       nm_setting_match_get_kernel_command_lines;
+       nm_setting_match_get_num_kernel_command_lines;
+       nm_setting_match_remove_kernel_command_line;
+       nm_setting_match_remove_kernel_command_line_by_value;
        nm_setting_sriov_add_vf;
        nm_setting_sriov_clear_vfs;
        nm_setting_sriov_get_autoprobe_drivers;
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 5d0774e91..2a0a58792 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -5994,7 +5994,6 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError **
        gs_free_error GError *local = NULL;
        gs_free char *conn_iface = NULL;
        NMDeviceClass *klass;
-       const char *const *patterns;
        NMSettingMatch *s_match;
 
        klass = NM_DEVICE_GET_CLASS (self);
@@ -6037,7 +6036,10 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError **
        s_match = (NMSettingMatch *) nm_connection_get_setting (connection,
                                                                NM_TYPE_SETTING_MATCH);
        if (s_match) {
+               const char *const *patterns;
                guint num_patterns = 0;
+               gs_free char *proc_cmdline = NULL;
+               gsize proc_cmdline_len = 0;
 
                patterns = nm_setting_match_get_interface_names (s_match, &num_patterns);
                if (!nm_wildcard_match_check (device_iface, patterns, num_patterns)) {
@@ -6045,6 +6047,18 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError **
                                                    "device does not satisfy match.interface-name property");
                        return FALSE;
                }
+
+               patterns = nm_setting_match_get_kernel_command_lines (s_match, &num_patterns);
+               if (g_file_get_contents ("/proc/cmdline", &proc_cmdline, &proc_cmdline_len, NULL)) {
+                       if (!nm_wildcard_match_check (proc_cmdline, patterns, num_patterns)) {
+                               nm_utils_error_set_literal (error, 
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+                                                           "device does not satisfy 
match.kernel-command-line property");
+                               _LOGD (LOGD_DEVICE, "does not satisfy match.kernel-command-line: %s", 
proc_cmdline);
+                               return FALSE;
+                       } else {
+                               _LOGD (LOGD_DEVICE, "satisfies match.kernel-command-line: %s", proc_cmdline);
+                       }
+               }
        }
 
        return TRUE;
-- 
2.24.1



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]