diff options
| author | Michael Biebl <biebl@debian.org> | 2017-01-25 21:09:50 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-01-25 21:09:50 +0100 |
| commit | 7f4dff3943c64e1d0e5d13b2ac915088dde165e6 (patch) | |
| tree | abfbc3a4102d3bba349b3e25265c2213ad636954 /src | |
| parent | d462f64d6044349b0a4e3581cf2c97bbab7aec97 (diff) | |
New upstream version 1.6.0 upstream/1.6.0
Diffstat (limited to 'src')
| -rw-r--r-- | src/devices/nm-device.c | 70 | ||||
| -rw-r--r-- | src/nm-active-connection.c | 17 | ||||
| -rw-r--r-- | src/nm-core-utils.c | 65 | ||||
| -rw-r--r-- | src/nm-exported-object.c | 47 | ||||
| -rw-r--r-- | src/nm-exported-object.h | 2 | ||||
| -rw-r--r-- | src/nm-manager.c | 7 | ||||
| -rw-r--r-- | src/settings/nm-settings.c | 6 | ||||
| -rw-r--r-- | src/tests/test-general.c | 106 |
8 files changed, 219 insertions, 101 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b614894e..1fcf965c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -281,8 +281,10 @@ typedef struct _NMDevicePrivate { guint32 ip4_address; NMActRequest * queued_act_request; - bool queued_act_request_is_waiting_for_carrier; - NMActRequest * act_request; + bool queued_act_request_is_waiting_for_carrier:1; + bool act_request_public:1; + NMActRequest *act_request; + gulong act_request_id; ActivationHandleData act_handle4; /* for layer2 and IPv4. */ ActivationHandleData act_handle6; guint recheck_assume_id; @@ -4207,6 +4209,7 @@ activate_stage1_device_prepare (NMDevice *self) _set_ip_state (self, AF_INET6, IP_NONE); /* Notify the new ActiveConnection along with the state change */ + priv->act_request_public = TRUE; _notify (self, PROP_ACTIVE_CONNECTION); nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); @@ -6669,8 +6672,9 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) NMSettingIPConfig *s_ip6; s_ip6 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6 && nm_streq0 (nm_setting_ip_config_get_method (s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + if ( s_ip6 + && !NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { /* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller * then 1280. * @@ -8122,20 +8126,46 @@ nm_device_activate_ip6_state_done (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->ip6_state == IP_DONE; } +/*****************************************************************************/ + static void -clear_act_request (NMDevice *self) +act_request_set_cb (NMActRequest *act_request, + GParamSpec *pspec, + NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + _notify (self, PROP_ACTIVE_CONNECTION); +} - if (!priv->act_request) +static void +act_request_set (NMDevice *self, NMActRequest *act_request) +{ + NMDevicePrivate *priv; + gs_unref_object NMActRequest *old_act_requst = NULL; + + nm_assert (NM_IS_DEVICE (self)); + nm_assert (!act_request || NM_IS_ACT_REQUEST (act_request)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if ( !priv->act_request_public + && priv->act_request == act_request) return; - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); + /* always clear the public flag. The few callers that set a new @act_request + * don't want that the property is public yet. */ + priv->act_request_public = FALSE; + + nm_clear_g_signal_handler (priv->act_request, &priv->act_request_id); - priv->master_ready_handled = FALSE; - nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id); + old_act_requst = priv->act_request; + priv->act_request = nm_g_object_ref (act_request); - g_clear_object (&priv->act_request); + if (act_request) { + priv->act_request_id = g_signal_connect (act_request, + "notify::"NM_EXPORTED_OBJECT_PATH, + G_CALLBACK (act_request_set_cb), + self); + } _notify (self, PROP_ACTIVE_CONNECTION); } @@ -8922,10 +8952,7 @@ _device_activate (NMDevice *self, NMActRequest *req) delete_on_deactivate_unschedule (self); - /* note: don't notify D-Bus of the new AC here, but do it later when - * changing state to PREPARE so that the two properties change together. - */ - priv->act_request = g_object_ref (req); + act_request_set (self, req); nm_device_activate_schedule_stage1_device_prepare (self); return TRUE; @@ -11409,7 +11436,14 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->needs_ip6_subnet = FALSE; - clear_act_request (self); + if (priv->act_request) { + nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE); + + priv->master_ready_handled = FALSE; + nm_clear_g_signal_handler (priv->act_request, &priv->master_ready_id); + + act_request_set (self, NULL); + } /* Clear legacy IPv4 address property */ if (priv->ip4_address) { @@ -11863,7 +11897,7 @@ _set_state_full (NMDevice *self, g_cancellable_cancel (priv->deactivating_cancellable); /* Cache the activation request for the dispatcher */ - req = priv->act_request ? g_object_ref (priv->act_request) : NULL; + req = nm_g_object_ref (priv->act_request); if (state <= NM_DEVICE_STATE_UNAVAILABLE) { if (available_connections_del_all (self)) @@ -13298,7 +13332,7 @@ get_property (GObject *object, guint prop_id, g_variant_new ("(uu)", priv->state, priv->state_reason)); break; case PROP_ACTIVE_CONNECTION: - nm_utils_g_value_set_object_path (value, priv->act_request); + nm_utils_g_value_set_object_path (value, priv->act_request_public ? priv->act_request : NULL); break; case PROP_DEVICE_TYPE: g_value_set_uint (value, priv->type); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 17fb82e5..38aadd27 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -157,6 +157,21 @@ _settings_connection_updated (NMSettingsConnection *connection, } static void +_settings_connection_removed (NMSettingsConnection *connection, + gpointer user_data) +{ + NMActiveConnection *self = user_data; + + /* Our settings connection is about to drop off. The next active connection + * cleanup is going to tear us down (at least until we grow the capability to + * re-link; in that case we'd just clean the references to the old connection here). + * Let's remove ourselves from the bus so that we're not exposed with a dangling + * reference to the setting connection once it's gone. */ + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self))) + nm_exported_object_unexport (NM_EXPORTED_OBJECT (self)); +} + +static void _set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connection) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); @@ -165,11 +180,13 @@ _set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connec return; if (priv->settings_connection) { g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_updated, self); + g_signal_handlers_disconnect_by_func (priv->settings_connection, _settings_connection_removed, self); g_clear_object (&priv->settings_connection); } if (connection) { priv->settings_connection = g_object_ref (connection); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self); + g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, (GCallback) _settings_connection_removed, self); } } diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 79f9e117..631540a1 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -1232,67 +1232,64 @@ typedef struct { } MatchDeviceData; static gboolean -match_device_s390_subchannels_parse (const char *s390_subchannels, guint32 *a, guint32 *b, guint32 *c) +match_device_s390_subchannels_parse (const char *s390_subchannels, guint32 *out_a, guint32 *out_b, guint32 *out_c) { - const int BUFSIZE = 10; - long unsigned int tmp; + const int BUFSIZE = 30; char buf[BUFSIZE + 1]; - const char *p = s390_subchannels; - int i = 0; + guint i = 0; char *pa = NULL, *pb = NULL, *pc = NULL; + gint64 a, b, c; nm_assert (s390_subchannels); - nm_assert (a != NULL); - nm_assert (*a == 0); - nm_assert (b != NULL); - nm_assert (*b == 0); - nm_assert (c != NULL); - nm_assert (*c == 0); - - /* sanity check */ + nm_assert (out_a); + nm_assert (out_b); + nm_assert (out_c); + if (!g_ascii_isxdigit (s390_subchannels[0])) return FALSE; /* Get the first channel */ - while (*p && (*p != ',')) { - if (!g_ascii_isxdigit (*p) && (*p != '.')) + for (i = 0; s390_subchannels[i]; i++) { + char ch = s390_subchannels[i]; + + if (!g_ascii_isxdigit (ch) && ch != '.') { + if (ch == ',') { + /* FIXME: currently we consider the first channel and ignore + * everything after the first ',' separator. Maybe we should + * validate all present channels? */ + break; + } return FALSE; /* Invalid chars */ + } if (i >= BUFSIZE) return FALSE; /* Too long to be a subchannel */ - buf[i++] = *p++; + buf[i] = ch; } buf[i] = '\0'; /* and grab each of its elements, there should be 3 */ pa = &buf[0]; - pb = strchr (buf, '.'); + pb = strchr (pa, '.'); if (pb) pc = strchr (pb + 1, '.'); - if (!pa || !pb || !pc) + if (!pb || !pc) return FALSE; - - /* Split the string */ *pb++ = '\0'; *pc++ = '\0'; - errno = 0; - tmp = strtoul (pa, NULL, 16); - if (errno) + a = _nm_utils_ascii_str_to_int64 (pa, 16, 0, G_MAXUINT32, -1); + if (a == -1) return FALSE; - *a = (guint32) tmp; - - errno = 0; - tmp = strtoul (pb, NULL, 16); - if (errno) + b = _nm_utils_ascii_str_to_int64 (pb, 16, 0, G_MAXUINT32, -1); + if (b == -1) return FALSE; - *b = (guint32) tmp; - - errno = 0; - tmp = strtoul (pc, NULL, 16); - if (errno) + c = _nm_utils_ascii_str_to_int64 (pc, 16, 0, G_MAXUINT32, -1); + if (c == -1) return FALSE; - *c = (guint32) tmp; + *out_a = (guint32) a; + *out_b = (guint32) b; + *out_c = (guint32) c; return TRUE; } diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c index a53a3123..cd0789ee 100644 --- a/src/nm-exported-object.c +++ b/src/nm-exported-object.c @@ -35,8 +35,16 @@ #define _ASSERT_NO_EARLY_EXPORT #endif +/*****************************************************************************/ + static gboolean quitting = FALSE; +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMExportedObject, + PROP_PATH, +); + typedef struct { GDBusInterfaceSkeleton *interface; guint property_changed_signal_id; @@ -677,6 +685,8 @@ nm_exported_object_export (NMExportedObject *self) nm_bus_manager_register_object (priv->bus_mgr, (GDBusObjectSkeleton *) self); + _notify (self, PROP_PATH); + return priv->path; } @@ -715,6 +725,8 @@ nm_exported_object_unexport (NMExportedObject *self) g_clear_pointer (&priv->path, g_free); nm_clear_g_source (&priv->notify_idle_id); + + _notify (self, PROP_PATH); } /*****************************************************************************/ @@ -959,6 +971,23 @@ vtype_found: /*****************************************************************************/ static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMExportedObject *self = NM_EXPORTED_OBJECT (object); + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void nm_exported_object_init (NMExportedObject *self) { NMExportedObjectPrivate *priv; @@ -987,7 +1016,8 @@ constructed (GObject *object) static void dispose (GObject *object) { - NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (NM_EXPORTED_OBJECT (object)); + NMExportedObject *self = NM_EXPORTED_OBJECT (object); + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); /* Objects should have already been unexported by their owner, unless * we are quitting, where many objects stick around until exit. @@ -995,10 +1025,10 @@ dispose (GObject *object) if (!quitting) { if (priv->path) { g_warn_if_reached (); - nm_exported_object_unexport (NM_EXPORTED_OBJECT (object)); + nm_exported_object_unexport (self); } - } else - g_clear_pointer (&priv->path, g_free); + } else if (nm_clear_g_free (&priv->path)) + _notify (self, PROP_PATH); nm_clear_g_source (&priv->notify_idle_id); @@ -1015,4 +1045,13 @@ nm_exported_object_class_init (NMExportedObjectClass *klass) object_class->constructed = constructed; object_class->notify = nm_exported_object_notify; object_class->dispose = dispose; + object_class->get_property = get_property; + + obj_properties[PROP_PATH] = + g_param_spec_string (NM_EXPORTED_OBJECT_PATH, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); } diff --git a/src/nm-exported-object.h b/src/nm-exported-object.h index 7d348129..47559a20 100644 --- a/src/nm-exported-object.h +++ b/src/nm-exported-object.h @@ -49,6 +49,8 @@ void nm_exported_object_skeleton_release (GDBusInterfaceSkeleton *interface); #define NM_IS_EXPORTED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_EXPORTED_OBJECT)) #define NM_EXPORTED_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectClass)) +#define NM_EXPORTED_OBJECT_PATH "path" + struct _NMExportedObjectPrivate; struct _NMExportedObject { diff --git a/src/nm-manager.c b/src/nm-manager.c index 867e0db6..0c1d36e1 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -3122,6 +3122,13 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } } + /* Now that we're activating a slave for that master, make sure the master just + * decides to go unmanaged while we're activating (perhaps because other slaves + * go away leaving him with no kids). + */ + nm_device_set_unmanaged_by_flags (master_device, NM_UNMANAGED_EXTERNAL_DOWN, + NM_UNMAN_FLAG_OP_FORGET, NM_DEVICE_STATE_REASON_USER_REQUESTED); + nm_active_connection_set_master (active, master_ac); _LOGD (LOGD_CORE, "Activation of '%s' depends on active connection %p %s", nm_settings_connection_get_id (connection), diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 6a920d5c..35790a12 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1112,8 +1112,10 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) openconnect_migrate_hack (NM_CONNECTION (connection)); g_object_ref (self); - g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, - G_CALLBACK (connection_removed), self); + /* This one unexports the connection, it needs to run late to give the active + * connection a chance to deal with its reference to this settings connection. */ + g_signal_connect_after (connection, NM_SETTINGS_CONNECTION_REMOVED, + G_CALLBACK (connection_removed), self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (connection_updated), self); g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE, diff --git a/src/tests/test-general.c b/src/tests/test-general.c index add12233..53c9c0d8 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -955,47 +955,38 @@ test_connection_sort_autoconnect_priority (void) /*****************************************************************************/ -static NMMatchSpecMatchType -_test_match_device_interface (const GSList *specs, const char *interface_name) -{ - return nm_match_spec_device (specs, interface_name, NULL, NULL, NULL); -} +#define MATCH_S390 "S390:" -static const char *_test_match_spec_all[] = { - "e", - "em", - "em*", - "em\\", - "em\\*", - "em\\1", - "em\\11", - "em\\2", - "em1", - "em11", - "em2", - "=em*", - NULL -}; - -static gboolean -_test_match_spec_contains (const char **matches, const char *match) +static NMMatchSpecMatchType +_test_match_spec_device (const GSList *specs, const char *match_str) { - guint i; - - for (i = 0; matches && matches[i]; i++) { - if (strcmp (match, matches[i]) == 0) - return TRUE; - } - return FALSE; + if (match_str && g_str_has_prefix (match_str, MATCH_S390)) + return nm_match_spec_device (specs, NULL, NULL, NULL, &match_str[NM_STRLEN (MATCH_S390)]); + return nm_match_spec_device (specs, match_str, NULL, NULL, NULL); } static void -_do_test_match_spec_device (const char *spec_str, const char **matches, const char **neg_matches) +_do_test_match_spec_device (const char *spec_str, const char **matches, const char **no_matches, const char **neg_matches) { - const char *m; GSList *specs, *specs_randperm = NULL, *specs_resplit, *specs_i, *specs_j; guint i; gs_free char *specs_joined = NULL; + const char *s; + static const char *no_matches_default[] = { + "e", + "em", + "em*", + "em\\", + "em\\*", + "em\\1", + "em\\11", + "em\\2", + "em1", + "em11", + "em2", + "=em*", + NULL + }; g_assert (spec_str); @@ -1019,20 +1010,25 @@ _do_test_match_spec_device (const char *spec_str, const char **matches, const ch specs_randperm = nmtst_rand_perm_gslist (NULL, g_slist_copy (specs)); for (i = 0; matches && matches[i]; i++) { - g_assert (_test_match_device_interface (specs, matches[i]) == NM_MATCH_SPEC_MATCH); - g_assert (_test_match_device_interface (specs_randperm, matches[i]) == NM_MATCH_SPEC_MATCH); + g_assert (_test_match_spec_device (specs, matches[i]) == NM_MATCH_SPEC_MATCH); + g_assert (_test_match_spec_device (specs_randperm, matches[i]) == NM_MATCH_SPEC_MATCH); } for (i = 0; neg_matches && neg_matches[i]; i++) { - g_assert (_test_match_device_interface (specs, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH); - g_assert (_test_match_device_interface (specs_randperm, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH); + g_assert (_test_match_spec_device (specs, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH); + g_assert (_test_match_spec_device (specs_randperm, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH); } - for (i = 0; (m = _test_match_spec_all[i]); i++) { - if (_test_match_spec_contains (matches, m)) - continue; - if (_test_match_spec_contains (neg_matches, m)) - continue; - g_assert (_test_match_device_interface (specs, m) == NM_MATCH_SPEC_NO_MATCH); - g_assert (_test_match_device_interface (specs_randperm, m) == NM_MATCH_SPEC_NO_MATCH); + for (i = 0; no_matches && no_matches[i]; i++) { + g_assert (_test_match_spec_device (specs, no_matches[i]) == NM_MATCH_SPEC_NO_MATCH); + g_assert (_test_match_spec_device (specs_randperm, no_matches[i]) == NM_MATCH_SPEC_NO_MATCH); + } + if (!no_matches) { + for (i = 0; (s = no_matches_default[i]); i++) { + if ( (matches && g_strv_contains (matches, s)) + || (neg_matches && g_strv_contains (neg_matches, s))) + continue; + g_assert (_test_match_spec_device (specs, s) == NM_MATCH_SPEC_NO_MATCH); + g_assert (_test_match_spec_device (specs_randperm, s) == NM_MATCH_SPEC_NO_MATCH); + } } g_slist_free (specs_randperm); @@ -1045,49 +1041,73 @@ test_match_spec_device (void) #define S(...) ((const char *[]) { __VA_ARGS__, NULL } ) _do_test_match_spec_device ("em1", S ("em1"), + NULL, NULL); _do_test_match_spec_device ("em1,em2", S ("em1", "em2"), + NULL, NULL); _do_test_match_spec_device ("em1,em2,interface-name:em2", S ("em1", "em2"), + NULL, NULL); _do_test_match_spec_device ("interface-name:em1", S ("em1"), + NULL, NULL); _do_test_match_spec_device ("interface-name:em*", S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"), + NULL, NULL); _do_test_match_spec_device ("interface-name:em\\*", S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"), + NULL, NULL); _do_test_match_spec_device ("interface-name:~em\\*", S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"), + NULL, NULL); _do_test_match_spec_device ("interface-name:=em*", S ("em*"), + NULL, NULL); _do_test_match_spec_device ("interface-name:em*,except:interface-name:em1*", S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em2", "em3"), + NULL, S ("em1", "em11")); _do_test_match_spec_device ("interface-name:em*,except:interface-name:=em*", S ("em", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"), + NULL, S ("em*")); _do_test_match_spec_device ("aa,bb,cc\\,dd,e,,", S ("aa", "bb", "cc,dd", "e"), + NULL, NULL); _do_test_match_spec_device ("aa;bb;cc\\;dd;e,;", S ("aa", "bb", "cc;dd", "e"), + NULL, NULL); _do_test_match_spec_device ("interface-name:em\\;1,em\\,2,\\,,\\\\,,em\\\\x", S ("em;1", "em,2", ",", "\\", "em\\x"), + NULL, NULL); _do_test_match_spec_device ("\\s\\s,\\sinterface-name:a,\\s,", S (" ", " ", " interface-name:a"), + NULL, NULL); _do_test_match_spec_device (" aa ; bb ; cc\\;dd ;e , ; \t\\t , ", S ("aa", "bb", "cc;dd", "e", "\t"), + NULL, + NULL); + + _do_test_match_spec_device ("s390-subchannels:0.0.1000\\,0.0.1001", + S (MATCH_S390"0.0.1000", MATCH_S390"0.0.1000,deadbeef", MATCH_S390"0.0.1000,0.0.1001", MATCH_S390"0.0.1000,0.0.1002"), + S (MATCH_S390"0.0.1001"), NULL); + _do_test_match_spec_device ("*,except:s390-subchannels:0.0.1000\\,0.0.1001", + NULL, + S (NULL), + S (MATCH_S390"0.0.1000", MATCH_S390"0.0.1000,deadbeef", MATCH_S390"0.0.1000,0.0.1001", MATCH_S390"0.0.1000,0.0.1002")); #undef S } |