summaryrefslogtreecommitdiff
path: root/src/tmpfiles/tmpfiles.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-10-26 20:56:37 +0200
committerLennart Poettering <lennart@poettering.net>2018-11-08 09:52:16 +0100
commit811a15877825da9e53f9a2a8603da34589af6bbb (patch)
tree9f10b225b978fb360cd7be59cda76e0e2060def6 /src/tmpfiles/tmpfiles.c
parent133bbca42e0ea4056e2151a1f5696b9ca8b6630b (diff)
downloadsystemd-811a15877825da9e53f9a2a8603da34589af6bbb.tar.gz
tmpfiles: create parents before children, but remove children before parents
Previously, we'd always process parents before children. With this change we are a bit more careful and create parents before children but clean up children before parents. The "done" boolean by item is replaced by a mask so that we can descent and ascend for the right operations only. See: #9508
Diffstat (limited to 'src/tmpfiles/tmpfiles.c')
-rw-r--r--src/tmpfiles/tmpfiles.c106
1 files changed, 79 insertions, 27 deletions
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index f7f72e9d0d..2b38068d58 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -136,13 +136,16 @@ typedef struct Item {
bool allow_failure:1;
- bool done:1;
+ OperationMask done;
} Item;
typedef struct ItemArray {
Item *items;
size_t n_items;
size_t allocated;
+
+ struct ItemArray *parent;
+ Set *children;
} ItemArray;
typedef enum DirectoryType {
@@ -2243,38 +2246,20 @@ static int clean_item(Item *i) {
}
}
-static int process_item_array(ItemArray *array, OperationMask operation);
-
static int process_item(Item *i, OperationMask operation) {
- int r, q, p, t = 0;
- _cleanup_free_ char *prefix = NULL;
+ OperationMask todo;
+ int r, q, p;
assert(i);
- if (i->done)
+ todo = operation & ~i->done;
+ if (todo == 0) /* Everything already done? */
return 0;
- i->done = true;
-
- prefix = malloc(strlen(i->path) + 1);
- if (!prefix)
- return log_oom();
-
- PATH_FOREACH_PREFIX(prefix, i->path) {
- ItemArray *j;
-
- j = ordered_hashmap_get(items, prefix);
- if (j) {
- int s;
-
- s = process_item_array(j, operation);
- if (s < 0 && t == 0)
- t = s;
- }
- }
+ i->done |= operation;
if (chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS, NULL) == -EREMOTE)
- return t;
+ return 0;
r = FLAGS_SET(operation, OPERATION_CREATE) ? create_item(i) : 0;
/* Failure can only be tolerated for create */
@@ -2284,8 +2269,7 @@ static int process_item(Item *i, OperationMask operation) {
q = FLAGS_SET(operation, OPERATION_REMOVE) ? remove_item(i) : 0;
p = FLAGS_SET(operation, OPERATION_CLEAN) ? clean_item(i) : 0;
- return t < 0 ? t :
- r < 0 ? r :
+ return r < 0 ? r :
q < 0 ? q :
p;
}
@@ -2296,6 +2280,24 @@ static int process_item_array(ItemArray *array, OperationMask operation) {
assert(array);
+ /* Create any parent first. */
+ if (FLAGS_SET(operation, OPERATION_CREATE) && array->parent)
+ r = process_item_array(array->parent, operation & OPERATION_CREATE);
+
+ /* Clean up all children first */
+ if ((operation & (OPERATION_REMOVE|OPERATION_CLEAN)) && !set_isempty(array->children)) {
+ Iterator i;
+ ItemArray *c;
+
+ SET_FOREACH(c, array->children, i) {
+ int k;
+
+ k = process_item_array(c, operation & (OPERATION_REMOVE|OPERATION_CLEAN));
+ if (k < 0 && r == 0)
+ r = k;
+ }
+ }
+
for (n = 0; n < array->n_items; n++) {
int k;
@@ -2328,6 +2330,7 @@ static void item_array_free(ItemArray *a) {
for (n = 0; n < a->n_items; n++)
item_free_contents(a->items + n);
+ set_free(a->children);
free(a->items);
free(a);
}
@@ -3117,6 +3120,43 @@ static int read_config_files(char **config_dirs, char **args, bool *invalid_conf
return 0;
}
+static int link_parent(ItemArray *a) {
+ const char *path;
+ char *prefix;
+ int r;
+
+ assert(a);
+
+ /* Finds the closestq "parent" item array for the specified item array. Then registers the specified item array
+ * as child of it, and fills the parent in, linking them both ways. This allows us to later create parents
+ * before their children, and clean up/remove children before their parents. */
+
+ if (a->n_items <= 0)
+ return 0;
+
+ path = a->items[0].path;
+ prefix = alloca(strlen(path) + 1);
+ PATH_FOREACH_PREFIX(prefix, path) {
+ ItemArray *j;
+
+ j = ordered_hashmap_get(items, prefix);
+ if (j) {
+ r = set_ensure_allocated(&j->children, NULL);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put(j->children, a);
+ if (r < 0)
+ return log_oom();
+
+ a->parent = j;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
int r, k, r_process = 0;
ItemArray *a;
@@ -3186,6 +3226,18 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
+ /* Let's now link up all child/parent relationships */
+ ORDERED_HASHMAP_FOREACH(a, items, iterator) {
+ r = link_parent(a);
+ if (r < 0)
+ goto finish;
+ }
+ ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
+ r = link_parent(a);
+ if (r < 0)
+ goto finish;
+ }
+
/* The non-globbing ones usually create things, hence we apply
* them first */
ORDERED_HASHMAP_FOREACH(a, items, iterator) {