+
+ break;
+ }
+
+ if ((r = label_fix(i->path, false)) < 0)
+ goto finish;
+
+ log_debug("%s created successfully.", i->path);
+
+finish:
+ if (fd >= 0)
+ close_nointr_nofail(fd);
+
+ return r;
+}
+
+static int remove_item(Item *i, const char *instance) {
+ int r;
+
+ assert(i);
+
+ switch (i->type) {
+
+ case CREATE_FILE:
+ case TRUNCATE_FILE:
+ case CREATE_DIRECTORY:
+ case IGNORE_PATH:
+ break;
+
+ case REMOVE_PATH:
+ if (remove(instance) < 0 && errno != ENOENT) {
+ log_error("remove(%s): %m", instance);
+ return -errno;
+ }
+
+ break;
+
+ case TRUNCATE_DIRECTORY:
+ case RECURSIVE_REMOVE_PATH:
+ if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH)) < 0 &&
+ r != -ENOENT) {
+ log_error("rm_rf(%s): %s", instance, strerror(-r));
+ return r;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+static int remove_item_glob(Item *i) {
+ assert(i);
+
+ switch (i->type) {
+
+ case CREATE_FILE:
+ case TRUNCATE_FILE:
+ case CREATE_DIRECTORY:
+ case IGNORE_PATH:
+ break;
+
+ case REMOVE_PATH:
+ case TRUNCATE_DIRECTORY:
+ case RECURSIVE_REMOVE_PATH: {
+ int r = 0, k;
+ glob_t g;
+ char **fn;
+
+ zero(g);
+
+ errno = 0;
+ if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) {
+
+ if (k != GLOB_NOMATCH) {
+ if (errno != 0)
+ errno = EIO;
+
+ log_error("glob(%s) failed: %m", i->path);
+ return -errno;
+ }
+ }
+
+ STRV_FOREACH(fn, g.gl_pathv)
+ if ((k = remove_item(i, *fn)) < 0)
+ r = k;
+
+ globfree(&g);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static int process_item(Item *i) {
+ int r, q, p;
+
+ assert(i);
+
+ r = arg_create ? create_item(i) : 0;
+ q = arg_remove ? remove_item_glob(i) : 0;
+ p = arg_clean ? clean_item(i) : 0;
+
+ if (r < 0)
+ return r;
+
+ if (q < 0)
+ return q;
+
+ return p;
+}
+
+static void item_free(Item *i) {
+ assert(i);
+
+ free(i->path);
+ free(i);
+}
+
+static bool item_equal(Item *a, Item *b) {
+ assert(a);
+ assert(b);
+
+ if (!streq_ptr(a->path, b->path))
+ return false;
+
+ if (a->type != b->type)
+ return false;
+
+ if (a->uid_set != b->uid_set ||
+ (a->uid_set && a->uid != b->uid))
+ return false;
+
+ if (a->gid_set != b->gid_set ||
+ (a->gid_set && a->gid != b->gid))
+ return false;
+
+ if (a->mode_set != b->mode_set ||
+ (a->mode_set && a->mode != b->mode))
+ return false;
+
+ if (a->age_set != b->age_set ||
+ (a->age_set && a->age != b->age))
+ return false;
+
+ return true;
+}
+
+static int parse_line(const char *fname, unsigned line, const char *buffer) {
+ Item *i, *existing;
+ char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
+ Hashmap *h;
+ int r;
+
+ assert(fname);
+ assert(line >= 1);
+ assert(buffer);
+
+ if (!(i = new0(Item, 1))) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ if (sscanf(buffer,
+ "%c "
+ "%ms "
+ "%ms "
+ "%ms "
+ "%ms "
+ "%ms",
+ &i->type,
+ &i->path,
+ &mode,
+ &user,
+ &group,
+ &age) < 2) {
+ log_error("[%s:%u] Syntax error.", fname, line);
+ r = -EIO;
+ goto finish;
+ }
+
+ if (i->type != CREATE_FILE &&
+ i->type != TRUNCATE_FILE &&
+ i->type != CREATE_DIRECTORY &&
+ i->type != TRUNCATE_DIRECTORY &&
+ i->type != IGNORE_PATH &&
+ i->type != REMOVE_PATH &&
+ i->type != RECURSIVE_REMOVE_PATH) {
+ log_error("[%s:%u] Unknown file type '%c'.", fname, line, i->type);
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ if (!path_is_absolute(i->path)) {
+ log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path);
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ path_kill_slashes(i->path);
+
+ if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
+ r = 0;
+ goto finish;
+ }
+
+ if (user && !streq(user, "-")) {
+ unsigned long lu;
+ struct passwd *p;
+
+ if (streq(user, "root") || streq(user, "0"))
+ i->uid = 0;
+ else if (safe_atolu(user, &lu) >= 0)
+ i->uid = (uid_t) lu;
+ else if ((p = getpwnam(user)))
+ i->uid = p->pw_uid;
+ else {
+ log_error("[%s:%u] Unknown user '%s'.", fname, line, user);
+ r = -ENOENT;
+ goto finish;
+ }
+
+ i->uid_set = true;
+ }
+
+ if (group && !streq(group, "-")) {
+ unsigned long lu;
+ struct group *g;
+
+ if (streq(group, "root") || streq(group, "0"))
+ i->gid = 0;
+ else if (safe_atolu(group, &lu) >= 0)
+ i->gid = (gid_t) lu;
+ else if ((g = getgrnam(group)))
+ i->gid = g->gr_gid;
+ else {
+ log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
+ r = -ENOENT;
+ goto finish;
+ }
+
+ i->gid_set = true;
+ }
+
+ if (mode && !streq(mode, "-")) {
+ unsigned m;
+
+ if (sscanf(mode, "%o", &m) != 1) {
+ log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
+ r = -ENOENT;
+ goto finish;
+ }
+
+ i->mode = m;
+ i->mode_set = true;
+ } else
+ i->mode = i->type == CREATE_DIRECTORY ? 0755 : 0644;
+
+ if (age && !streq(age, "-")) {
+ if (parse_usec(age, &i->age) < 0) {
+ log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
+ r = -EBADMSG;
+ goto finish;