]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tmpfiles: move static vars into Context object
authorLennart Poettering <lennart@poettering.net>
Wed, 9 Aug 2023 09:37:46 +0000 (11:37 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 10 Aug 2023 18:12:06 +0000 (19:12 +0100)
Same as #28722, but for tmpfiles rather than sysusers

src/tmpfiles/tmpfiles.c

index b8fb5c3b3ba159718ea60f793b64dd9a65fa4dc6..e765db4895da4fc03e4c4f739ca98f9781eda2e9 100644 (file)
@@ -212,12 +212,11 @@ static ImagePolicy *arg_image_policy = NULL;
 
 #define MAX_DEPTH 256
 
-static OrderedHashmap *items = NULL, *globs = NULL;
-static Set *unix_sockets = NULL;
+typedef struct Context {
+        OrderedHashmap *items, *globs;
+        Set *unix_sockets;
+} Context;
 
-STATIC_DESTRUCTOR_REGISTER(items, ordered_hashmap_freep);
-STATIC_DESTRUCTOR_REGISTER(globs, ordered_hashmap_freep);
-STATIC_DESTRUCTOR_REGISTER(unix_sockets, set_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_include_prefixes, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
@@ -232,6 +231,15 @@ static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
 
+static void context_done(Context *c) {
+        assert(c);
+
+        ordered_hashmap_free(c->items);
+        ordered_hashmap_free(c->globs);
+
+        set_free(c->unix_sockets);
+}
+
 /* Different kinds of errors that mean that information is not available in the environment. */
 static inline bool ERRNO_IS_NOINFO(int r) {
         return IN_SET(abs(r),
@@ -428,12 +436,12 @@ static struct Item* find_glob(OrderedHashmap *h, const char *match) {
         return NULL;
 }
 
-static int load_unix_sockets(void) {
+static int load_unix_sockets(Context *c) {
         _cleanup_set_free_ Set *sockets = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
-        if (unix_sockets)
+        if (c->unix_sockets)
                 return 0;
 
         /* We maintain a cache of the sockets we found in /proc/net/unix to speed things up a little. */
@@ -480,17 +488,18 @@ static int load_unix_sockets(void) {
                         return log_warning_errno(r, "Failed to add AF_UNIX socket to set, ignoring: %m");
         }
 
-        unix_sockets = TAKE_PTR(sockets);
+        c->unix_sockets = TAKE_PTR(sockets);
         return 1;
 }
 
-static bool unix_socket_alive(const char *fn) {
+static bool unix_socket_alive(Context *c, const char *fn) {
+        assert(c);
         assert(fn);
 
-        if (load_unix_sockets() < 0)
+        if (load_unix_sockets(c) < 0)
                 return true;     /* We don't know, so assume yes */
 
-        return set_contains(unix_sockets, fn);
+        return set_contains(c->unix_sockets, fn);
 }
 
 /* Accessors for the argument in binary format */
@@ -595,6 +604,7 @@ static bool needs_cleanup(
 }
 
 static int dir_cleanup(
+                Context *c,
                 Item *i,
                 const char *p,
                 DIR *d,
@@ -612,6 +622,10 @@ static int dir_cleanup(
         bool deleted = false;
         int r = 0;
 
+        assert(c);
+        assert(i);
+        assert(d);
+
         FOREACH_DIRENT_ALL(de, d, break) {
                 _cleanup_free_ char *sub_path = NULL;
                 nsec_t atime_nsec, mtime_nsec, ctime_nsec, btime_nsec;
@@ -689,12 +703,12 @@ static int dir_cleanup(
                 }
 
                 /* Is there an item configured for this path? */
-                if (ordered_hashmap_get(items, sub_path)) {
+                if (ordered_hashmap_get(c->items, sub_path)) {
                         log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
                         continue;
                 }
 
-                if (find_glob(globs, sub_path)) {
+                if (find_glob(c->globs, sub_path)) {
                         log_debug("Ignoring \"%s\": a separate glob exists.", sub_path);
                         continue;
                 }
@@ -727,7 +741,7 @@ static int dir_cleanup(
                                         continue;
                                 }
 
-                                q = dir_cleanup(i,
+                                q = dir_cleanup(c, i,
                                                 sub_path, sub_dir,
                                                 atime_nsec, mtime_nsec, cutoff_nsec,
                                                 rootdev_major, rootdev_minor,
@@ -782,7 +796,7 @@ static int dir_cleanup(
                         }
 
                         /* Ignore sockets that are listed in /proc/net/unix */
-                        if (S_ISSOCK(sx.stx_mode) && unix_socket_alive(sub_path)) {
+                        if (S_ISSOCK(sx.stx_mode) && unix_socket_alive(c, sub_path)) {
                                 log_debug("Skipping \"%s\": live socket.", sub_path);
                                 continue;
                         }
@@ -892,6 +906,7 @@ static mode_t process_mask_perms(mode_t mode, mode_t current) {
 }
 
 static int fd_set_perms(
+                Context *c,
                 Item *i,
                 int fd,
                 const char *path,
@@ -905,6 +920,7 @@ static int fd_set_perms(
         gid_t new_gid;
         int r;
 
+        assert(c);
         assert(i);
         assert(fd >= 0);
         assert(path);
@@ -1038,12 +1054,14 @@ static int path_open_safe(const char *path) {
 }
 
 static int path_set_perms(
+                Context *c,
                 Item *i,
                 const char *path,
                 CreationMode creation) {
 
         _cleanup_close_ int fd = -EBADF;
 
+        assert(c);
         assert(i);
         assert(path);
 
@@ -1051,7 +1069,7 @@ static int path_set_perms(
         if (fd < 0)
                 return fd;
 
-        return fd_set_perms(i, fd, path, /* st= */ NULL, creation);
+        return fd_set_perms(c, i, fd, path, /* st= */ NULL, creation);
 }
 
 static int parse_xattrs_from_arg(Item *i) {
@@ -1091,12 +1109,14 @@ static int parse_xattrs_from_arg(Item *i) {
 }
 
 static int fd_set_xattrs(
+                Context *c,
                 Item *i,
                 int fd,
                 const char *path,
                 const struct stat *st,
                 CreationMode creation) {
 
+        assert(c);
         assert(i);
         assert(fd >= 0);
         assert(path);
@@ -1111,12 +1131,14 @@ static int fd_set_xattrs(
 }
 
 static int path_set_xattrs(
+                Context *c,
                 Item *i,
                 const char *path,
                 CreationMode creation) {
 
         _cleanup_close_ int fd = -EBADF;
 
+        assert(c);
         assert(i);
         assert(path);
 
@@ -1124,7 +1146,7 @@ static int path_set_xattrs(
         if (fd < 0)
                 return fd;
 
-        return fd_set_xattrs(i, fd, path, /* st = */ NULL, creation);
+        return fd_set_xattrs(c, i, fd, path, /* st = */ NULL, creation);
 }
 
 static int parse_acls_from_arg(Item *item) {
@@ -1277,6 +1299,7 @@ finish:
 }
 
 static int path_set_acl(
+                Context *c,
                 const char *path,
                 const char *pretty,
                 acl_type_t type,
@@ -1287,8 +1310,9 @@ static int path_set_acl(
         _cleanup_(acl_freep) acl_t dup = NULL;
         int r;
 
-        /* Returns 0 for success, positive error if already warned,
-         * negative error otherwise. */
+        assert(c);
+
+        /* Returns 0 for success, positive error if already warned, negative error otherwise. */
 
         if (modify) {
                 r = acls_for_file(path, type, acl, &dup);
@@ -1332,6 +1356,7 @@ static int path_set_acl(
 #endif
 
 static int fd_set_acls(
+                Context *c,
                 Item *item,
                 int fd,
                 const char *path,
@@ -1343,6 +1368,7 @@ static int fd_set_acls(
         _cleanup_(acl_freep) acl_t access_with_exec_parsed = NULL;
         struct stat stbuf;
 
+        assert(c);
         assert(item);
         assert(fd >= 0);
         assert(path);
@@ -1373,13 +1399,13 @@ static int fd_set_acls(
                 if (r < 0)
                         return log_error_errno(r, "Failed to parse conditionalized execute bit for \"%s\": %m", path);
 
-                r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, access_with_exec_parsed, item->append_or_force);
+                r = path_set_acl(c, FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, access_with_exec_parsed, item->append_or_force);
         } else if (item->acl_access)
-                r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
+                r = path_set_acl(c, FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
 
         /* set only default acls to folders */
         if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
-                r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
+                r = path_set_acl(c, FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
 
         if (ERRNO_IS_NOT_SUPPORTED(r)) {
                 log_debug_errno(r, "ACLs not supported by file system at %s", path);
@@ -1399,11 +1425,17 @@ static int fd_set_acls(
         return r;
 }
 
-static int path_set_acls(Item *item, const char *path, CreationMode creation) {
+static int path_set_acls(
+                Context *c,
+                Item *item,
+                const char *path,
+                CreationMode creation) {
+
         int r = 0;
 #if HAVE_ACL
         _cleanup_close_ int fd = -EBADF;
 
+        assert(c);
         assert(item);
         assert(path);
 
@@ -1411,7 +1443,7 @@ static int path_set_acls(Item *item, const char *path, CreationMode creation) {
         if (fd < 0)
                 return fd;
 
-        r = fd_set_acls(item, fd, path, /* st= */ NULL, creation);
+        r = fd_set_acls(c, item, fd, path, /* st= */ NULL, creation);
 #endif
         return r;
 }
@@ -1501,6 +1533,7 @@ static int parse_attribute_from_arg(Item *item) {
 }
 
 static int fd_set_attribute(
+                Context *c,
                 Item *item,
                 int fd,
                 const char *path,
@@ -1512,6 +1545,7 @@ static int fd_set_attribute(
         unsigned f;
         int r;
 
+        assert(c);
         assert(item);
         assert(fd >= 0);
         assert(path);
@@ -1556,9 +1590,17 @@ static int fd_set_attribute(
         return 0;
 }
 
-static int path_set_attribute(Item *item, const char *path, CreationMode creation) {
+static int path_set_attribute(
+                Context *c,
+                Item *item,
+                const char *path,
+                CreationMode creation) {
+
         _cleanup_close_ int fd = -EBADF;
 
+        assert(c);
+        assert(item);
+
         if (!item->attribute_set || item->attribute_mask == 0)
                 return 0;
 
@@ -1566,7 +1608,7 @@ static int path_set_attribute(Item *item, const char *path, CreationMode creatio
         if (fd < 0)
                 return fd;
 
-        return fd_set_attribute(item, fd, path, /* st= */ NULL, creation);
+        return fd_set_attribute(c, item, fd, path, /* st= */ NULL, creation);
 }
 
 static int write_argument_data(Item *i, int fd, const char *path) {
@@ -1590,11 +1632,12 @@ static int write_argument_data(Item *i, int fd, const char *path) {
         return 0;
 }
 
-static int write_one_file(Item *i, const char *path, CreationMode creation) {
+static int write_one_file(Context *c, Item *i, const char *path, CreationMode creation) {
         _cleanup_close_ int fd = -EBADF, dir_fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         int r;
 
+        assert(c);
         assert(i);
         assert(path);
         assert(i->type == WRITE_FILE);
@@ -1633,16 +1676,21 @@ static int write_one_file(Item *i, const char *path, CreationMode creation) {
         if (r < 0)
                 return r;
 
-        return fd_set_perms(i, fd, path, NULL, creation);
+        return fd_set_perms(c, i, fd, path, NULL, creation);
 }
 
-static int create_file(Item *i, const char *path) {
+static int create_file(
+                Context *c,
+                Item *i,
+                const char *path) {
+
         _cleanup_close_ int fd = -EBADF, dir_fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         struct stat stbuf, *st = NULL;
         CreationMode creation;
         int r = 0;
 
+        assert(c);
         assert(i);
         assert(path);
         assert(i->type == CREATE_FILE);
@@ -1698,10 +1746,14 @@ static int create_file(Item *i, const char *path) {
                 creation = CREATION_NORMAL;
         }
 
-        return fd_set_perms(i, fd, path, st, creation);
+        return fd_set_perms(c, i, fd, path, st, creation);
 }
 
-static int truncate_file(Item *i, const char *path) {
+static int truncate_file(
+                Context *c,
+                Item *i,
+                const char *path) {
+
         _cleanup_close_ int fd = -EBADF, dir_fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         struct stat stbuf, *st = NULL;
@@ -1709,6 +1761,7 @@ static int truncate_file(Item *i, const char *path) {
         bool erofs = false;
         int r = 0;
 
+        assert(c);
         assert(i);
         assert(path);
         assert(i->type == TRUNCATE_FILE || (i->type == CREATE_FILE && i->append_or_force));
@@ -1787,10 +1840,10 @@ static int truncate_file(Item *i, const char *path) {
                         return r;
         }
 
-        return fd_set_perms(i, fd, path, st, creation);
+        return fd_set_perms(c, i, fd, path, st, creation);
 }
 
-static int copy_files(Item *i) {
+static int copy_files(Context *c, Item *i) {
         _cleanup_close_ int dfd = -EBADF, fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         struct stat st, a;
@@ -1834,7 +1887,7 @@ static int copy_files(Item *i) {
                 return 0;
         }
 
-        return fd_set_perms(i, fd, i->path, &st, _CREATION_MODE_INVALID);
+        return fd_set_perms(c, i, fd, i->path, &st, _CREATION_MODE_INVALID);
 }
 
 static int create_directory_or_subvolume(
@@ -1922,11 +1975,16 @@ static int create_directory_or_subvolume(
         return fd;
 }
 
-static int create_directory(Item *i, const char *path) {
+static int create_directory(
+                Context *c,
+                Item *i,
+                const char *path) {
+
         _cleanup_close_ int fd = -EBADF;
         CreationMode creation;
         struct stat st;
 
+        assert(c);
         assert(i);
         assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
 
@@ -1936,15 +1994,20 @@ static int create_directory(Item *i, const char *path) {
         if (fd < 0)
                 return fd;
 
-        return fd_set_perms(i, fd, path, &st, creation);
+        return fd_set_perms(c, i, fd, path, &st, creation);
 }
 
-static int create_subvolume(Item *i, const char *path) {
+static int create_subvolume(
+                Context *c,
+                Item *i,
+                const char *path) {
+
         _cleanup_close_ int fd = -EBADF;
         CreationMode creation;
         struct stat st;
         int r, q = 0;
 
+        assert(c);
         assert(i);
         assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
 
@@ -1971,18 +2034,24 @@ static int create_subvolume(Item *i, const char *path) {
                         log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
         }
 
-        r = fd_set_perms(i, fd, path, &st, creation);
+        r = fd_set_perms(c, i, fd, path, &st, creation);
         if (q < 0) /* prefer the quota change error from above */
                 return q;
 
         return r;
 }
 
-static int empty_directory(Item *i, const char *path, CreationMode creation) {
+static int empty_directory(
+                Context *c,
+                Item *i,
+                const char *path,
+                CreationMode creation) {
+
         _cleanup_close_ int fd = -EBADF;
         struct stat st;
         int r;
 
+        assert(c);
         assert(i);
         assert(i->type == EMPTY_DIRECTORY);
 
@@ -2005,16 +2074,21 @@ static int empty_directory(Item *i, const char *path, CreationMode creation) {
                 return 0;
         }
 
-        return fd_set_perms(i, fd, path, &st, creation);
+        return fd_set_perms(c, i, fd, path, &st, creation);
 }
 
-static int create_device(Item *i, mode_t file_type) {
+static int create_device(
+                Context *c,
+                Item *i,
+                mode_t file_type) {
+
         _cleanup_close_ int dfd = -EBADF, fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         CreationMode creation;
         struct stat st;
         int r;
 
+        assert(c);
         assert(i);
         assert(IN_SET(i->type, CREATE_BLOCK_DEVICE, CREATE_CHAR_DEVICE));
         assert(IN_SET(file_type, S_IFBLK, S_IFCHR));
@@ -2104,7 +2178,7 @@ static int create_device(Item *i, mode_t file_type) {
                   i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
                   i->path, major(i->mode), minor(i->mode));
 
-        return fd_set_perms(i, fd, i->path, &st, creation);
+        return fd_set_perms(c, i, fd, i->path, &st, creation);
 
 handle_privilege:
         log_debug_errno(r,
@@ -2113,13 +2187,14 @@ handle_privilege:
         return 0;
 }
 
-static int create_fifo(Item *i) {
+static int create_fifo(Context *c, Item *i) {
         _cleanup_close_ int pfd = -EBADF, fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         CreationMode creation;
         struct stat st;
         int r;
 
+        assert(c);
         assert(i);
         assert(i->type == CREATE_FIFO);
 
@@ -2195,10 +2270,10 @@ static int create_fifo(Item *i) {
 
         log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
 
-        return fd_set_perms(i, fd, i->path, &st, creation);
+        return fd_set_perms(c, i, fd, i->path, &st, creation);
 }
 
-static int create_symlink(Item *i) {
+static int create_symlink(Context *c, Item *i) {
         _cleanup_close_ int pfd = -EBADF, fd = -EBADF;
         _cleanup_free_ char *bn = NULL;
         CreationMode creation;
@@ -2206,6 +2281,7 @@ static int create_symlink(Item *i) {
         bool good = false;
         int r;
 
+        assert(c);
         assert(i);
 
         r = path_extract_filename(i->path, &bn);
@@ -2284,13 +2360,14 @@ static int create_symlink(Item *i) {
         }
 
         log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
-        return fd_set_perms(i, fd, i->path, &st, creation);
+        return fd_set_perms(c, i, fd, i->path, &st, creation);
 }
 
-typedef int (*action_t)(Item *i, const char *path, CreationMode creation);
-typedef int (*fdaction_t)(Item *i, int fd, const char *path, const struct stat *st, CreationMode creation);
+typedef int (*action_t)(Context *c, Item *i, const char *path, CreationMode creation);
+typedef int (*fdaction_t)(Context *c, Item *i, int fd, const char *path, const struct stat *st, CreationMode creation);
 
 static int item_do(
+                Context *c,
                 Item *i,
                 int fd,
                 const char *path,
@@ -2300,6 +2377,7 @@ static int item_do(
         struct stat st;
         int r = 0, q;
 
+        assert(c);
         assert(i);
         assert(path);
         assert(fd >= 0);
@@ -2310,7 +2388,7 @@ static int item_do(
         }
 
         /* This returns the first error we run into, but nevertheless tries to go on */
-        r = action(i, fd, path, &st, creation);
+        r = action(c, i, fd, path, &st, creation);
 
         if (S_ISDIR(st.st_mode)) {
                 _cleanup_closedir_ DIR *d = NULL;
@@ -2342,7 +2420,7 @@ static int item_do(
                                         q = log_oom();
                                 else
                                         /* Pass ownership of dirent fd over */
-                                        q = item_do(i, de_fd, de_path, CREATION_EXISTING, action);
+                                        q = item_do(c, i, de_fd, de_path, CREATION_EXISTING, action);
                         }
 
                         if (q < 0 && r == 0)
@@ -2354,19 +2432,22 @@ finish:
         return r;
 }
 
-static int glob_item(Item *i, action_t action) {
+static int glob_item(Context *c, Item *i, action_t action) {
         _cleanup_globfree_ glob_t g = {
                 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
         };
         int r = 0, k;
 
+        assert(c);
+        assert(i);
+
         k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
         if (k < 0 && k != -ENOENT)
                 return log_error_errno(k, "glob(%s) failed: %m", i->path);
 
         STRV_FOREACH(fn, g.gl_pathv) {
                 /* We pass CREATION_EXISTING here, since if we are globbing for it, it always has to exist */
-                k = action(i, *fn, CREATION_EXISTING);
+                k = action(c, i, *fn, CREATION_EXISTING);
                 if (k < 0 && r == 0)
                         r = k;
         }
@@ -2374,7 +2455,11 @@ static int glob_item(Item *i, action_t action) {
         return r;
 }
 
-static int glob_item_recursively(Item *i, fdaction_t action) {
+static int glob_item_recursively(
+                Context *c,
+                Item *i,
+                fdaction_t action) {
+
         _cleanup_globfree_ glob_t g = {
                 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
         };
@@ -2400,7 +2485,7 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
                         continue;
                 }
 
-                k = item_do(i, fd, *fn, CREATION_EXISTING, action);
+                k = item_do(c, i, fd, *fn, CREATION_EXISTING, action);
                 if (k < 0 && r == 0)
                         r = k;
 
@@ -2584,9 +2669,10 @@ static int mkdir_parents_item(Item *i, mode_t child_mode) {
         return 0;
 }
 
-static int create_item(Item *i) {
+static int create_item(Context *c, Item *i) {
         int r;
 
+        assert(c);
         assert(i);
 
         log_debug("Running create action for entry %c %s", (char) i->type, i->path);
@@ -2606,9 +2692,9 @@ static int create_item(Item *i) {
                         return r;
 
                 if ((i->type == CREATE_FILE && i->append_or_force) || i->type == TRUNCATE_FILE)
-                        r = truncate_file(i, i->path);
+                        r = truncate_file(c, i, i->path);
                 else
-                        r = create_file(i, i->path);
+                        r = create_file(c, i, i->path);
                 if (r < 0)
                         return r;
                 break;
@@ -2618,13 +2704,13 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
-                r = copy_files(i);
+                r = copy_files(c, i);
                 if (r < 0)
                         return r;
                 break;
 
         case WRITE_FILE:
-                r = glob_item(i, write_one_file);
+                r = glob_item(c, i, write_one_file);
                 if (r < 0)
                         return r;
 
@@ -2636,7 +2722,7 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
-                r = create_directory(i, i->path);
+                r = create_directory(c, i, i->path);
                 if (r < 0)
                         return r;
                 break;
@@ -2648,13 +2734,13 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
-                r = create_subvolume(i, i->path);
+                r = create_subvolume(c, i, i->path);
                 if (r < 0)
                         return r;
                 break;
 
         case EMPTY_DIRECTORY:
-                r = glob_item(i, empty_directory);
+                r = glob_item(c, i, empty_directory);
                 if (r < 0)
                         return r;
                 break;
@@ -2664,7 +2750,7 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
-                r = create_fifo(i);
+                r = create_fifo(c, i);
                 if (r < 0)
                         return r;
                 break;
@@ -2674,7 +2760,7 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
-                r = create_symlink(i);
+                r = create_symlink(c, i);
                 if (r < 0)
                         return r;
 
@@ -2694,7 +2780,7 @@ static int create_item(Item *i) {
                 if (r < 0)
                         return r;
 
-                r = create_device(i, i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
+                r = create_device(c, i, i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
                 if (r < 0)
                         return r;
 
@@ -2702,49 +2788,49 @@ static int create_item(Item *i) {
 
         case ADJUST_MODE:
         case RELABEL_PATH:
-                r = glob_item(i, path_set_perms);
+                r = glob_item(c, i, path_set_perms);
                 if (r < 0)
                         return r;
                 break;
 
         case RECURSIVE_RELABEL_PATH:
-                r = glob_item_recursively(i, fd_set_perms);
+                r = glob_item_recursively(c, i, fd_set_perms);
                 if (r < 0)
                         return r;
                 break;
 
         case SET_XATTR:
-                r = glob_item(i, path_set_xattrs);
+                r = glob_item(c, i, path_set_xattrs);
                 if (r < 0)
                         return r;
                 break;
 
         case RECURSIVE_SET_XATTR:
-                r = glob_item_recursively(i, fd_set_xattrs);
+                r = glob_item_recursively(c, i, fd_set_xattrs);
                 if (r < 0)
                         return r;
                 break;
 
         case SET_ACL:
-                r = glob_item(i, path_set_acls);
+                r = glob_item(c, i, path_set_acls);
                 if (r < 0)
                         return r;
                 break;
 
         case RECURSIVE_SET_ACL:
-                r = glob_item_recursively(i, fd_set_acls);
+                r = glob_item_recursively(c, i, fd_set_acls);
                 if (r < 0)
                         return r;
                 break;
 
         case SET_ATTRIBUTE:
-                r = glob_item(i, path_set_attribute);
+                r = glob_item(c, i, path_set_attribute);
                 if (r < 0)
                         return r;
                 break;
 
         case RECURSIVE_SET_ATTRIBUTE:
-                r = glob_item_recursively(i, fd_set_attribute);
+                r = glob_item_recursively(c, i, fd_set_attribute);
                 if (r < 0)
                         return r;
                 break;
@@ -2753,9 +2839,15 @@ static int create_item(Item *i) {
         return 0;
 }
 
-static int remove_item_instance(Item *i, const char *instance, CreationMode creation) {
+static int remove_item_instance(
+                Context *c,
+                Item *i,
+                const char *instance,
+                CreationMode creation) {
+
         int r;
 
+        assert(c);
         assert(i);
 
         switch (i->type) {
@@ -2782,9 +2874,10 @@ static int remove_item_instance(Item *i, const char *instance, CreationMode crea
         return 0;
 }
 
-static int remove_item(Item *i) {
+static int remove_item(Context *c, Item *i) {
         int r;
 
+        assert(c);
         assert(i);
 
         log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
@@ -2802,7 +2895,7 @@ static int remove_item(Item *i) {
 
         case REMOVE_PATH:
         case RECURSIVE_REMOVE_PATH:
-                return glob_item(i, remove_item_instance);
+                return glob_item(c, i, remove_item_instance);
 
         default:
                 return 0;
@@ -2827,6 +2920,7 @@ static char *age_by_to_string(AgeBy ab, bool is_dir) {
 }
 
 static int clean_item_instance(
+                Context *c,
                 Item *i,
                 const char* instance,
                 CreationMode creation) {
@@ -2893,7 +2987,7 @@ static int clean_item_instance(
                           ab_f, ab_d);
         }
 
-        return dir_cleanup(i, instance, d,
+        return dir_cleanup(c, i, instance, d,
                            load_statx_timestamp_nsec(&sx.stx_atime),
                            load_statx_timestamp_nsec(&sx.stx_mtime),
                            cutoff * NSEC_PER_USEC,
@@ -2902,12 +2996,14 @@ static int clean_item_instance(
                            i->age_by_file, i->age_by_dir);
 }
 
-static int clean_item(Item *i) {
+static int clean_item(Context *c, Item *i) {
+        assert(c);
         assert(i);
 
         log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
 
         switch (i->type) {
+
         case CREATE_DIRECTORY:
         case CREATE_SUBVOLUME:
         case CREATE_SUBVOLUME_INHERIT_QUOTA:
@@ -2915,22 +3011,29 @@ static int clean_item(Item *i) {
         case TRUNCATE_DIRECTORY:
         case IGNORE_PATH:
         case COPY_FILES:
-                clean_item_instance(i, i->path, CREATION_EXISTING);
+                clean_item_instance(c, i, i->path, CREATION_EXISTING);
                 return 0;
+
         case EMPTY_DIRECTORY:
         case IGNORE_DIRECTORY_PATH:
-                return glob_item(i, clean_item_instance);
+                return glob_item(c, i, clean_item_instance);
+
         default:
                 return 0;
         }
 }
 
-static int process_item(Item *i, OperationMask operation) {
+static int process_item(
+                Context *c,
+                Item *i,
+                OperationMask operation) {
+
         OperationMask todo;
         _cleanup_free_ char *_path = NULL;
         const char *path;
         int r, q, p;
 
+        assert(c);
         assert(i);
 
         todo = operation & ~i->done;
@@ -2959,37 +3062,42 @@ static int process_item(Item *i, OperationMask operation) {
         if (r < 0)
                 log_debug_errno(r, "Failed to determine whether '%s' is below autofs, ignoring: %m", i->path);
 
-        r = FLAGS_SET(operation, OPERATION_CREATE) ? create_item(i) : 0;
+        r = FLAGS_SET(operation, OPERATION_CREATE) ? create_item(c, i) : 0;
         /* Failure can only be tolerated for create */
         if (i->allow_failure)
                 r = 0;
 
-        q = FLAGS_SET(operation, OPERATION_REMOVE) ? remove_item(i) : 0;
-        p = FLAGS_SET(operation, OPERATION_CLEAN) ? clean_item(i) : 0;
+        q = FLAGS_SET(operation, OPERATION_REMOVE) ? remove_item(c, i) : 0;
+        p = FLAGS_SET(operation, OPERATION_CLEAN) ? clean_item(c, i) : 0;
 
         return r < 0 ? r :
                 q < 0 ? q :
                 p;
 }
 
-static int process_item_array(ItemArray *array, OperationMask operation) {
+static int process_item_array(
+                Context *c,
+                ItemArray *array,
+                OperationMask operation) {
+
         int r = 0;
         size_t n;
 
+        assert(c);
         assert(array);
 
         /* Create any parent first. */
         if (FLAGS_SET(operation, OPERATION_CREATE) && array->parent)
-                r = process_item_array(array->parent, operation & OPERATION_CREATE);
+                r = process_item_array(c, array->parent, operation & OPERATION_CREATE);
 
         /* Clean up all children first */
         if ((operation & (OPERATION_REMOVE|OPERATION_CLEAN)) && !set_isempty(array->children)) {
-                ItemArray *c;
+                ItemArray *cc;
 
-                SET_FOREACH(c, array->children) {
+                SET_FOREACH(cc, array->children) {
                         int k;
 
-                        k = process_item_array(c, operation & (OPERATION_REMOVE|OPERATION_CLEAN));
+                        k = process_item_array(c, cc, operation & (OPERATION_REMOVE|OPERATION_CLEAN));
                         if (k < 0 && r == 0)
                                 r = k;
                 }
@@ -2998,7 +3106,7 @@ static int process_item_array(ItemArray *array, OperationMask operation) {
         for (n = 0; n < array->n_items; n++) {
                 int k;
 
-                k = process_item(array->items + n, operation);
+                k = process_item(c, array->items + n, operation);
                 if (k < 0 && r == 0)
                         r = k;
         }
@@ -3315,6 +3423,7 @@ static bool is_duplicated_item(ItemArray *existing, const Item *i) {
 }
 
 static int parse_line(
+                Context *c,
                 const char *fname,
                 unsigned line,
                 const char *buffer,
@@ -3334,6 +3443,7 @@ static int parse_line(
         bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
                 unbase64 = false, from_cred = false, missing_user_or_group = false;
 
+        assert(c);
         assert(fname);
         assert(line >= 1);
         assert(buffer);
@@ -3786,7 +3896,7 @@ static int parse_line(
                 i.age_set = true;
         }
 
-        h = needs_glob(i.type) ? globs : items;
+        h = needs_glob(i.type) ? c->globs : c->items;
 
         existing = ordered_hashmap_get(h, i.path);
         if (existing) {
@@ -4053,6 +4163,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 static int read_config_file(
+                Context *c,
                 char **config_dirs,
                 const char *fn,
                 bool ignore_enoent,
@@ -4066,6 +4177,7 @@ static int read_config_file(
         ItemArray *ia;
         int r = 0;
 
+        assert(c);
         assert(fn);
 
         if (streq(fn, "-")) {
@@ -4106,7 +4218,7 @@ static int read_config_file(
                 if (IN_SET(*l, 0, '#'))
                         continue;
 
-                k = parse_line(fn, v, l, &invalid_line, &uid_cache, &gid_cache);
+                k = parse_line(c, fn, v, l, &invalid_line, &uid_cache, &gid_cache);
                 if (k < 0) {
                         if (invalid_line)
                                 /* Allow reporting with a special code if the caller requested this */
@@ -4118,7 +4230,7 @@ static int read_config_file(
         }
 
         /* we have to determine age parameter for each entry of type X */
-        ORDERED_HASHMAP_FOREACH(ia, globs)
+        ORDERED_HASHMAP_FOREACH(ia, c->globs)
                 for (size_t ni = 0; ni < ia->n_items; ni++) {
                         ItemArray *ja;
                         Item *i = ia->items + ni, *candidate_item = NULL;
@@ -4126,7 +4238,7 @@ static int read_config_file(
                         if (i->type != IGNORE_DIRECTORY_PATH)
                                 continue;
 
-                        ORDERED_HASHMAP_FOREACH(ja, items)
+                        ORDERED_HASHMAP_FOREACH(ja, c->items)
                                 for (size_t nj = 0; nj < ja->n_items; nj++) {
                                         Item *j = ja->items + nj;
 
@@ -4163,11 +4275,17 @@ static int read_config_file(
         return r;
 }
 
-static int parse_arguments(char **config_dirs, char **args, bool *invalid_config) {
+static int parse_arguments(
+                Context *c,
+                char **config_dirs,
+                char **args,
+                bool *invalid_config) {
         int r;
 
+        assert(c);
+
         STRV_FOREACH(arg, args) {
-                r = read_config_file(config_dirs, *arg, false, invalid_config);
+                r = read_config_file(c, config_dirs, *arg, false, invalid_config);
                 if (r < 0)
                         return r;
         }
@@ -4175,11 +4293,18 @@ static int parse_arguments(char **config_dirs, char **args, bool *invalid_config
         return 0;
 }
 
-static int read_config_files(char **config_dirs, char **args, bool *invalid_config) {
+static int read_config_files(
+                Context *c,
+                char **config_dirs,
+                char **args,
+                bool *invalid_config) {
+
         _cleanup_strv_free_ char **files = NULL;
         _cleanup_free_ char *p = NULL;
         int r;
 
+        assert(c);
+
         r = conf_files_list_with_replacement(arg_root, config_dirs, arg_replace, &files, &p);
         if (r < 0)
                 return r;
@@ -4188,22 +4313,25 @@ static int read_config_files(char **config_dirs, char **args, bool *invalid_conf
                 if (p && path_equal(*f, p)) {
                         log_debug("Parsing arguments at position \"%s\"%s", *f, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
 
-                        r = parse_arguments(config_dirs, args, invalid_config);
+                        r = parse_arguments(c, config_dirs, args, invalid_config);
                         if (r < 0)
                                 return r;
                 } else
                         /* Just warn, ignore result otherwise.
                          * read_config_file() has some debug output, so no need to print anything. */
-                        (void) read_config_file(config_dirs, *f, true, invalid_config);
+                        (void) read_config_file(c, config_dirs, *f, true, invalid_config);
 
         return 0;
 }
 
-static int read_credential_lines(bool *invalid_config) {
+static int read_credential_lines(Context *c, bool *invalid_config) {
+
         _cleanup_free_ char *j = NULL;
         const char *d;
         int r;
 
+        assert(c);
+
         r = get_credentials_dir(&d);
         if (r == -ENXIO)
                 return 0;
@@ -4214,15 +4342,16 @@ static int read_credential_lines(bool *invalid_config) {
         if (!j)
                 return log_oom();
 
-        (void) read_config_file(/* config_dirs= */ NULL, j, /* ignore_enoent= */ true, invalid_config);
+        (void) read_config_file(c, /* config_dirs= */ NULL, j, /* ignore_enoent= */ true, invalid_config);
         return 0;
 }
 
-static int link_parent(ItemArray *a) {
+static int link_parent(Context *c, ItemArray *a) {
         const char *path;
         char *prefix;
         int r;
 
+        assert(c);
         assert(a);
 
         /* Finds the closest "parent" item array for the specified item array. Then registers the specified item array
@@ -4237,9 +4366,9 @@ static int link_parent(ItemArray *a) {
         PATH_FOREACH_PREFIX(prefix, path) {
                 ItemArray *j;
 
-                j = ordered_hashmap_get(items, prefix);
+                j = ordered_hashmap_get(c->items, prefix);
                 if (!j)
-                        j = ordered_hashmap_get(globs, prefix);
+                        j = ordered_hashmap_get(c->globs, prefix);
                 if (j) {
                         r = set_ensure_put(&j->children, NULL, a);
                         if (r < 0)
@@ -4262,6 +4391,7 @@ static int run(int argc, char *argv[]) {
         _cleanup_(umount_and_freep) char *mounted_dir = NULL;
 #endif
         _cleanup_strv_free_ char **config_dirs = NULL;
+        _cleanup_(context_done) Context c = {};
         bool invalid_config = false;
         ItemArray *a;
         enum {
@@ -4364,9 +4494,9 @@ static int run(int argc, char *argv[]) {
         assert(!arg_image);
 #endif
 
-        items = ordered_hashmap_new(&item_array_hash_ops);
-        globs = ordered_hashmap_new(&item_array_hash_ops);
-        if (!items || !globs)
+        c.items = ordered_hashmap_new(&item_array_hash_ops);
+        c.globs = ordered_hashmap_new(&item_array_hash_ops);
+        if (!c.items || !c.globs)
                 return log_oom();
 
         /* If command line arguments are specified along with --replace, read all
@@ -4376,24 +4506,24 @@ static int run(int argc, char *argv[]) {
          * read configuration and execute it.
          */
         if (arg_replace || optind >= argc)
-                r = read_config_files(config_dirs, argv + optind, &invalid_config);
+                r = read_config_files(&c, config_dirs, argv + optind, &invalid_config);
         else
-                r = parse_arguments(config_dirs, argv + optind, &invalid_config);
+                r = parse_arguments(&c, config_dirs, argv + optind, &invalid_config);
         if (r < 0)
                 return r;
 
-        r = read_credential_lines(&invalid_config);
+        r = read_credential_lines(&c, &invalid_config);
         if (r < 0)
                 return r;
 
         /* Let's now link up all child/parent relationships */
-        ORDERED_HASHMAP_FOREACH(a, items) {
-                r = link_parent(a);
+        ORDERED_HASHMAP_FOREACH(a, c.items) {
+                r = link_parent(&c, a);
                 if (r < 0)
                         return r;
         }
-        ORDERED_HASHMAP_FOREACH(a, globs) {
-                r = link_parent(a);
+        ORDERED_HASHMAP_FOREACH(a, c.globs) {
+                r = link_parent(&c, a);
                 if (r < 0)
                         return r;
         }
@@ -4414,15 +4544,15 @@ static int run(int argc, char *argv[]) {
                         continue;
 
                 /* The non-globbing ones usually create things, hence we apply them first */
-                ORDERED_HASHMAP_FOREACH(a, items) {
-                        k = process_item_array(a, op);
+                ORDERED_HASHMAP_FOREACH(a, c.items) {
+                        k = process_item_array(&c, a, op);
                         if (k < 0 && r >= 0)
                                 r = k;
                 }
 
                 /* The globbing ones usually alter things, hence we apply them second. */
-                ORDERED_HASHMAP_FOREACH(a, globs) {
-                        k = process_item_array(a, op);
+                ORDERED_HASHMAP_FOREACH(a, c.globs) {
+                        k = process_item_array(&c, a, op);
                         if (k < 0 && r >= 0)
                                 r = k;
                 }