sysupdate: Allow patterns to match path with directories

`MatchPattern` for regular-file and directory as target can now match
subdirectories This is useful to install files for examples in `.extra.d`
directories:

```
[Target]
Type=regular-file
Path=/EFI/Linux
PathRelativeTo=boot
MatchPattern=gnomeos_@v.efi.extra.d/apparmor.addon.efi
```

The if the directories in the path do not exist, they will be created.  Whereas
the part in `Path` is not created.
This commit is contained in:
Valentin David
2023-09-28 11:41:29 +02:00
parent 18c3ffbfcc
commit 8b051623cd
5 changed files with 141 additions and 35 deletions
+54 -26
View File
@@ -69,30 +69,16 @@ static int resource_add_instance(
return 0;
}
static int resource_load_from_directory(
static int resource_load_from_directory_recursive(
Resource *rr,
DIR* d,
const char* relpath,
mode_t m) {
_cleanup_closedir_ DIR *d = NULL;
int r;
assert(rr);
assert(IN_SET(rr->type, RESOURCE_TAR, RESOURCE_REGULAR_FILE, RESOURCE_DIRECTORY, RESOURCE_SUBVOLUME));
assert(IN_SET(m, S_IFREG, S_IFDIR));
d = opendir(rr->path);
if (!d) {
if (errno == ENOENT) {
log_debug("Directory %s does not exist, not loading any resources.", rr->path);
return 0;
}
return log_error_errno(errno, "Failed to open directory '%s': %m", rr->path);
}
for (;;) {
_cleanup_(instance_metadata_destroy) InstanceMetadata extracted_fields = INSTANCE_METADATA_NULL;
_cleanup_free_ char *joined = NULL;
_cleanup_free_ char *joined = NULL, *rel_joined = NULL;
Instance *instance;
struct dirent *de;
struct stat st;
@@ -111,7 +97,7 @@ static int resource_load_from_directory(
break;
case DT_DIR:
if (m != S_IFDIR)
if (!IN_SET(m, S_IFDIR, S_IFREG))
continue;
break;
@@ -132,16 +118,36 @@ static int resource_load_from_directory(
return log_error_errno(errno, "Failed to stat %s/%s: %m", rr->path, de->d_name);
}
if ((st.st_mode & S_IFMT) != m)
if (!(S_ISDIR(st.st_mode) && S_ISREG(m)) && ((st.st_mode & S_IFMT) != m))
continue;
r = pattern_match_many(rr->patterns, de->d_name, &extracted_fields);
if (r < 0)
rel_joined = path_join(relpath, de->d_name);
if (!rel_joined)
return log_oom();
r = pattern_match_many(rr->patterns, rel_joined, &extracted_fields);
if (r == PATTERN_MATCH_RETRY) {
_cleanup_closedir_ DIR *subdir = NULL;
subdir = xopendirat(dirfd(d), rel_joined, 0);
if (!subdir)
continue;
r = resource_load_from_directory_recursive(rr, subdir, rel_joined, m);
if (r < 0)
return r;
if (r == 0)
continue;
}
else if (r < 0)
return log_error_errno(r, "Failed to match pattern: %m");
if (r == 0)
else if (r == PATTERN_MATCH_NO)
continue;
joined = path_join(rr->path, de->d_name);
if (de->d_type == DT_DIR && m != S_IFDIR)
continue;
joined = path_join(rr->path, rel_joined);
if (!joined)
return log_oom();
@@ -160,6 +166,28 @@ static int resource_load_from_directory(
return 0;
}
static int resource_load_from_directory(
Resource *rr,
mode_t m) {
_cleanup_closedir_ DIR *d = NULL;
assert(rr);
assert(IN_SET(rr->type, RESOURCE_TAR, RESOURCE_REGULAR_FILE, RESOURCE_DIRECTORY, RESOURCE_SUBVOLUME));
assert(IN_SET(m, S_IFREG, S_IFDIR));
d = opendir(rr->path);
if (!d) {
if (errno == ENOENT) {
log_debug_errno(errno, "Directory %s does not exist, not loading any resources: %m", rr->path);
return 0;
}
return log_error_errno(errno, "Failed to open directory '%s': %m", rr->path);
}
return resource_load_from_directory_recursive(rr, d, NULL, m);
}
static int resource_load_from_blockdev(Resource *rr) {
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
@@ -204,7 +232,7 @@ static int resource_load_from_blockdev(Resource *rr) {
r = pattern_match_many(rr->patterns, pinfo.label, &extracted_fields);
if (r < 0)
return log_error_errno(r, "Failed to match pattern: %m");
if (r == 0)
if (IN_SET(r, PATTERN_MATCH_NO, PATTERN_MATCH_RETRY))
continue;
r = resource_add_instance(rr, pinfo.device, &extracted_fields, &instance);
@@ -402,7 +430,7 @@ static int resource_load_from_web(
r = pattern_match_many(rr->patterns, fn, &extracted_fields);
if (r < 0)
return log_error_errno(r, "Failed to match pattern: %m");
if (r > 0) {
if (r == PATTERN_MATCH_YES) {
_cleanup_free_ char *path = NULL;
r = import_url_append_component(rr->path, fn, &path);