conf: recurse into arrays before matching

When the value looks like an array, recurse into it and do the matching
on the array items instead of the whole value.
This commit is contained in:
Wim Taymans 2026-05-26 09:42:49 +02:00
parent 784a9dd00f
commit f195140702
2 changed files with 33 additions and 9 deletions

View file

@ -527,6 +527,7 @@ The general rules object follows the following pattern:
{ {
# <key> = <value> # <key> = <value>
# all keys must match the value. ! negates. ~ starts regex. # all keys must match the value. ! negates. ~ starts regex.
# if <value> is an array, matching is done on its elements.
#application.process.binary = "teams" #application.process.binary = "teams"
#application.name = "~speech-dispatcher.*" #application.name = "~speech-dispatcher.*"
@ -644,6 +645,19 @@ matches = [
] ]
``` ```
When the value is an array, the match is performed on the array elements until
one succeeds. For example:
```css
matches = [
{
pipewire.sec.gids = 42
}
]
```
Matches `pipewire.sec.gids = [ 10, 20, 42, 1000 ]`.
# CONTEXT PROPERTIES RULES @IDX@ pipewire.conf context.properties.rules # CONTEXT PROPERTIES RULES @IDX@ pipewire.conf context.properties.rules

View file

@ -640,12 +640,12 @@ static int load_module(struct pw_context *context, const char *key, const char *
SPA_EXPORT SPA_EXPORT
bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool condition) bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool condition)
{ {
struct spa_json it[1]; struct spa_json it[2];
const char *as = arr->cur; const char *as = arr->cur;
int az = (int)(arr->end - arr->cur), r, count = 0; int az = (int)(arr->end - arr->cur), r, count = 0;
while ((r = spa_json_enter_object(arr, &it[0])) > 0) { while ((r = spa_json_enter_object(arr, &it[0])) > 0) {
char key[256], val[1024]; char key[256], val[1024], v[1024];
const char *str, *value; const char *str, *value;
int match = 0, fail = 0; int match = 0, fail = 0;
int len; int len;
@ -691,6 +691,7 @@ bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool
if (is_null && str == NULL) if (is_null && str == NULL)
success = !success; success = !success;
} else { } else {
regex_t preg;
/* only unescape string once or again after modifier */ /* only unescape string once or again after modifier */
if (!parse_string) { if (!parse_string) {
memmove(val, value+skip, len-skip); memmove(val, value+skip, len-skip);
@ -702,21 +703,30 @@ bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool
} }
if (reg) { if (reg) {
regex_t preg;
int res; int res;
if ((res = regcomp(&preg, val, REG_EXTENDED | REG_NOSUB)) != 0) { if ((res = regcomp(&preg, val, REG_EXTENDED | REG_NOSUB)) != 0) {
char errbuf[1024]; char errbuf[1024];
regerror(res, &preg, errbuf, sizeof(errbuf)); regerror(res, &preg, errbuf, sizeof(errbuf));
pw_log_warn("invalid regex %s: %s in '%.*s'", pw_log_warn("invalid regex %s: %s in '%.*s'",
val, errbuf, az, as); val, errbuf, az, as);
} else { reg = false;
if (regexec(&preg, str, 0, NULL, 0) == 0)
success = !success;
regfree(&preg);
} }
} else if (strcmp(str, val) == 0) {
success = !success;
} }
if (spa_json_begin_array_relax(&it[1], str, strlen(str)) > 0) {
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0) {
if ((reg && regexec(&preg, v, 0, NULL, 0) == 0) ||
spa_streq(v, val)) {
success = !success;
break;
}
}
}
else if ((reg && regexec(&preg, str, 0, NULL, 0) == 0) ||
spa_streq(str, val))
success = !success;
if (reg)
regfree(&preg);
} }
if (success) { if (success) {
match++; match++;