X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Ftmpfiles.c;h=3a1985a36334c1b01dd1b6651fa39dbb89fd71fd;hp=0c3b88d35b19a1aaf56247802e95b88665911c7c;hb=4b67834e9f8a336dbc917f3bf212550e61cc98b4;hpb=35b8ca3aaf8cb044ad76675dfcad89e000dd4a5c diff --git a/src/tmpfiles.c b/src/tmpfiles.c index 0c3b88d35..3a1985a36 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 */ @@ -57,6 +56,7 @@ enum { TRUNCATE_FILE = 'F', CREATE_DIRECTORY = 'd', TRUNCATE_DIRECTORY = 'D', + CREATE_FIFO = 'p', /* These ones take globs */ IGNORE_PATH = 'x', @@ -466,6 +466,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); @@ -505,6 +506,48 @@ static int create_item(Item *i) { } break; + + case CREATE_FIFO: + + u = umask(0); + r = mkfifo(i->path, i->mode); + umask(u); + + if (r < 0 && errno != EEXIST) { + log_error("Failed to create fifo %s: %m", i->path); + r = -errno; + goto finish; + } + + if (stat(i->path, &st) < 0) { + log_error("stat(%s) failed: %m", i->path); + r = -errno; + goto finish; + } + + if (!S_ISFIFO(st.st_mode)) { + log_error("%s is not a fifo.", i->path); + r = -EEXIST; + goto finish; + } + + if (i->mode_set) + if (chmod(i->path, i->mode) < 0) { + log_error("chmod(%s) failed: %m", i->path); + r = -errno; + goto finish; + } + + if (i->uid_set || i->gid_set) + if (chown(i->path, + i->uid_set ? i->uid : (uid_t) -1, + i->gid_set ? i->gid : (gid_t) -1) < 0) { + log_error("chown(%s) failed: %m", i->path); + r = -errno; + goto finish; + } + + break; } if ((r = label_fix(i->path, false)) < 0) @@ -529,6 +572,7 @@ static int remove_item(Item *i, const char *instance) { case CREATE_FILE: case TRUNCATE_FILE: case CREATE_DIRECTORY: + case CREATE_FIFO: case IGNORE_PATH: break; @@ -562,6 +606,7 @@ static int remove_item_glob(Item *i) { case CREATE_FILE: case TRUNCATE_FILE: case CREATE_DIRECTORY: + case CREATE_FIFO: case IGNORE_PATH: break; @@ -623,9 +668,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); @@ -659,6 +734,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i->type != TRUNCATE_FILE && i->type != CREATE_DIRECTORY && i->type != TRUNCATE_DIRECTORY && + i->type != CREATE_FIFO && i->type != IGNORE_PATH && i->type != REMOVE_PATH && i->type != RECURSIVE_REMOVE_PATH) { @@ -681,18 +757,11 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } 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 { + const char *u = user; + + r = get_user_creds(&u, &i->uid, NULL, NULL); + if (r < 0) { log_error("[%s:%u] Unknown user '%s'.", fname, line, user); - r = -ENOENT; goto finish; } @@ -700,18 +769,11 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } 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 { + const char *g = group; + + r = get_group_creds(&g, &i->gid); + if (r < 0) { log_error("[%s:%u] Unknown group '%s'.", fname, line, group); - r = -ENOENT; goto finish; } @@ -742,13 +804,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; } @@ -768,19 +836,6 @@ finish: return r; } -static int scandir_filter(const struct dirent *d) { - assert(d); - - if (ignore_file(d->d_name)) - return 0; - - if (d->d_type != DT_REG && - d->d_type != DT_LNK) - return 0; - - return endswith(d->d_name, ".conf"); -} - static int help(void) { printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" @@ -875,6 +930,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { return -errno; } + log_debug("apply: %s\n", fn); for (;;) { char line[LINE_MAX], *l; int k; @@ -937,48 +993,33 @@ int main(int argc, char *argv[]) { r = EXIT_FAILURE; } else { - int n, j; - struct dirent **de = NULL; - - if ((n = scandir("/etc/tmpfiles.d/", &de, scandir_filter, alphasort)) < 0) { - - if (errno != ENOENT) { - log_error("Failed to enumerate /etc/tmpfiles.d/ files: %m"); - r = EXIT_FAILURE; - } - + char **files, **f; + + r = conf_files_list(&files, ".conf", + "/run/tmpfiles.d", + "/etc/tmpfiles.d", + "/usr/local/lib/tmpfiles.d", + "/usr/lib/tmpfiles.d", + NULL); + if (r < 0) { + r = EXIT_FAILURE; + log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r)); goto finish; } - for (j = 0; j < n; j++) { - int k; - char *fn; - - k = asprintf(&fn, "/etc/tmpfiles.d/%s", de[j]->d_name); - free(de[j]); - - if (k < 0) { - log_error("Failed to allocate file name."); - r = EXIT_FAILURE; - continue; - } - - if (read_config_file(fn, true) < 0) + STRV_FOREACH(f, files) { + if (read_config_file(*f, true) < 0) r = EXIT_FAILURE; - - free(fn); } - free(de); + strv_free(files); } HASHMAP_FOREACH(i, globs, iterator) - if (process_item(i) < 0) - r = EXIT_FAILURE; + process_item(i); HASHMAP_FOREACH(i, items, iterator) - if (process_item(i) < 0) - r = EXIT_FAILURE; + process_item(i); finish: while ((i = hashmap_steal_first(items)))