X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Ftmpfiles.c;h=2526d1e915d1aace1598a4238c3251124e75d56c;hb=4fe60156fc45e34c7bcba4779123e15620532dff;hp=01668da87e142c8a3711424e1c05e47c55080425;hpb=17b9052533551fc786f73f1a2898ac6a28fe1210;p=elogind.git diff --git a/src/tmpfiles.c b/src/tmpfiles.c index 01668da87..2526d1e91 100644 --- a/src/tmpfiles.c +++ b/src/tmpfiles.c @@ -47,9 +47,8 @@ /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates * them in the file system. This is intended to be used to create - * properly owned directories beneath /tmp, /var/tmp, /var/run and - * /var/lock which are volatile and hence need to be recreated on - * bootup. */ + * properly owned directories beneath /tmp, /var/tmp, /run, which are + * volatile and hence need to be recreated on bootup. */ enum { /* These ones take file names */ @@ -147,6 +146,8 @@ static void load_unix_sockets(void) { if (!(s = strdup(p))) goto fail; + path_kill_slashes(s); + if ((k = set_put(unix_sockets, s)) < 0) { free(s); @@ -301,6 +302,10 @@ static int dir_cleanup( if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path)) continue; + /* Ignore device nodes */ + if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) + continue; + age = MAX3(timespec_load(&s.st_mtim), timespec_load(&s.st_atim), timespec_load(&s.st_ctim)); @@ -460,6 +465,7 @@ static int create_item(Item *i) { case CREATE_DIRECTORY: u = umask(0); + mkdir_parents(i->path, 0755); r = mkdir(i->path, i->mode); umask(u); @@ -501,7 +507,7 @@ static int create_item(Item *i) { break; } - if ((r = label_fix(i->path)) < 0) + if ((r = label_fix(i->path, false)) < 0) goto finish; log_debug("%s created successfully.", i->path); @@ -617,9 +623,39 @@ static void item_free(Item *i) { 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; + Item *i, *existing; char *mode = NULL, *user = NULL, *group = NULL, *age = NULL; + Hashmap *h; int r; assert(fname); @@ -736,13 +772,19 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i->age_set = true; } - if ((r = hashmap_put(needs_glob(i->type) ? globs : items, i->path, i)) < 0) { - if (r == -EEXIST) { + h = needs_glob(i->type) ? globs : items; + + if ((existing = hashmap_get(h, i->path))) { + + /* Two identical items are fine */ + if (!item_equal(existing, i)) log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); - r = 0; - goto finish; - } + r = 0; + goto finish; + } + + if ((r = hashmap_put(h, i->path, i)) < 0) { log_error("Failed to insert item %s: %s", i->path, strerror(-r)); goto finish; } @@ -769,7 +811,8 @@ static int scandir_filter(const struct dirent *d) { return 0; if (d->d_type != DT_REG && - d->d_type != DT_LNK) + d->d_type != DT_LNK && + d->d_type != DT_UNKNOWN) return 0; return endswith(d->d_name, ".conf"); @@ -846,7 +889,7 @@ static int parse_argv(int argc, char *argv[]) { } if (!arg_clean && !arg_create && !arg_remove) { - log_error("You need to specify at leat one of --clean, --create or --remove."); + log_error("You need to specify at least one of --clean, --create or --remove."); return -EINVAL; }