X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Ftmpfiles%2Ftmpfiles.c;h=5eca82ad26c423c3ca7320eb20eecb9e98c83de6;hp=4a76a2f778bbfbdcbab1bb8b7c9310dd1fdb086a;hb=5c7951141fa9f33e1b97de97586cc16bce2776e0;hpb=99d680acf192a7193c3de73b525ffbc24c25cca8 diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 4a76a2f77..5eca82ad2 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -43,6 +43,7 @@ #include "log.h" #include "util.h" #include "macro.h" +#include "missing.h" #include "mkdir.h" #include "path-util.h" #include "strv.h" @@ -104,7 +105,8 @@ static bool arg_create = false; static bool arg_clean = false; static bool arg_remove = false; -static const char *arg_prefix = NULL; +static char **include_prefixes = NULL; +static char **exclude_prefixes = NULL; static const char conf_file_dirs[] = "/etc/tmpfiles.d\0" @@ -134,7 +136,7 @@ static struct Item* find_glob(Hashmap *h, const char *match) { } static void load_unix_sockets(void) { - FILE _cleanup_fclose_ *f = NULL; + _cleanup_fclose_ FILE *f = NULL; char line[LINE_MAX]; if (unix_sockets) @@ -185,13 +187,9 @@ static void load_unix_sockets(void) { path_kill_slashes(s); - k = set_put(unix_sockets, s); - if (k < 0) { - free(s); - - if (k != -EEXIST) - goto fail; - } + k = set_consume(unix_sockets, s); + if (k < 0 && k != -EEXIST) + goto fail; } return; @@ -268,7 +266,7 @@ static int dir_cleanup( while ((dent = readdir(d))) { struct stat s; usec_t age; - char _cleanup_free_ *sub_path = NULL; + _cleanup_free_ char *sub_path = NULL; if (streq(dent->d_name, ".") || streq(dent->d_name, "..")) @@ -320,7 +318,7 @@ static int dir_cleanup( if (maxdepth <= 0) log_warning("Reached max depth on %s.", sub_path); else { - DIR _cleanup_closedir_ *sub_dir; + _cleanup_closedir_ DIR *sub_dir; int q; sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME); @@ -453,18 +451,17 @@ static int item_set_perms(Item *i, const char *path) { static int write_one_file(Item *i, const char *path) { int r, e, fd, flags; struct stat st; - mode_t u; flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND : i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0; - u = umask(0); - label_context_set(path, S_IFREG); - fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode); - e = errno; - label_context_clear(); - umask(u); - errno = e; + RUN_WITH_UMASK(0) { + label_context_set(path, S_IFREG); + fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode); + e = errno; + label_context_clear(); + errno = e; + } if (fd < 0) { if (i->type == WRITE_FILE && errno == ENOENT) @@ -515,7 +512,7 @@ static int write_one_file(Item *i, const char *path) { } static int recursive_relabel_children(Item *i, const char *path) { - DIR _cleanup_closedir_ *d; + _cleanup_closedir_ DIR *d; int ret = 0; /* This returns the first error we run into, but nevertheless @@ -530,7 +527,7 @@ static int recursive_relabel_children(Item *i, const char *path) { union dirent_storage buf; bool is_dir; int r; - char _cleanup_free_ *entry_path = NULL; + _cleanup_free_ char *entry_path = NULL; r = readdir_r(d, &buf.de, &de); if (r != 0) { @@ -601,34 +598,31 @@ static int recursive_relabel(Item *i, const char *path) { static int glob_item(Item *i, int (*action)(Item *, const char *)) { int r = 0, k; - glob_t g; + _cleanup_globfree_ glob_t g = {}; char **fn; - zero(g); - errno = 0; - if ((k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g)) != 0) { - + k = glob(i->path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + if (k != 0) if (k != GLOB_NOMATCH) { - if (errno != 0) + if (errno > 0) errno = EIO; log_error("glob(%s) failed: %m", i->path); return -errno; } - } - STRV_FOREACH(fn, g.gl_pathv) - if ((k = action(i, *fn)) < 0) + STRV_FOREACH(fn, g.gl_pathv) { + k = action(i, *fn); + if (k < 0) r = k; + } - globfree(&g); return r; } static int create_item(Item *i) { int r, e; - mode_t u; struct stat st; assert(i); @@ -657,10 +651,10 @@ static int create_item(Item *i) { case TRUNCATE_DIRECTORY: case CREATE_DIRECTORY: - u = umask(0); - mkdir_parents_label(i->path, 0755); - r = mkdir(i->path, i->mode); - umask(u); + RUN_WITH_UMASK(0000) { + mkdir_parents_label(i->path, 0755); + r = mkdir(i->path, i->mode); + } if (r < 0 && errno != EEXIST) { log_error("Failed to create directory %s: %m", i->path); @@ -685,9 +679,9 @@ static int create_item(Item *i) { case CREATE_FIFO: - u = umask(0); - r = mkfifo(i->path, i->mode); - umask(u); + RUN_WITH_UMASK(0000) { + r = mkfifo(i->path, i->mode); + } if (r < 0 && errno != EEXIST) { log_error("Failed to create fifo %s: %m", i->path); @@ -746,7 +740,7 @@ static int create_item(Item *i) { if (have_effective_cap(CAP_MKNOD) == 0) { /* In a container we lack CAP_MKNOD. We - shouldnt attempt to create the device node in + shouldn't attempt to create the device node in that case to avoid noise, and we don't support virtualized devices in containers anyway. */ @@ -756,13 +750,13 @@ static int create_item(Item *i) { file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR); - u = umask(0); - label_context_set(i->path, file_type); - r = mknod(i->path, i->mode | file_type, i->major_minor); - e = errno; - label_context_clear(); - umask(u); - errno = e; + RUN_WITH_UMASK(0000) { + label_context_set(i->path, file_type); + r = mknod(i->path, i->mode | file_type, i->major_minor); + e = errno; + label_context_clear(); + errno = e; + } if (r < 0 && errno != EEXIST) { log_error("Failed to create device node %s: %m", i->path); @@ -790,7 +784,7 @@ static int create_item(Item *i) { r = glob_item(i, item_set_perms); if (r < 0) - return 0; + return r; break; case RECURSIVE_RELABEL_PATH: @@ -882,7 +876,7 @@ static int remove_item(Item *i) { } static int clean_item_instance(Item *i, const char* instance) { - DIR _cleanup_closedir_ *d = NULL; + _cleanup_closedir_ DIR *d = NULL; struct stat s, ps; bool mountpoint; int r; @@ -978,6 +972,12 @@ static void item_free(Item *i) { free(i); } +static inline void item_freep(Item **i) { + if (*i) + item_free(*i); +} +#define _cleanup_item_free_ _cleanup_(item_freep) + static bool item_equal(Item *a, Item *b) { assert(a); assert(b); @@ -1019,9 +1019,28 @@ static bool item_equal(Item *a, Item *b) { return true; } +static bool should_include_path(const char *path) { + char **prefix; + + STRV_FOREACH(prefix, exclude_prefixes) { + if (path_startswith(path, *prefix)) + return false; + } + + STRV_FOREACH(prefix, include_prefixes) { + if (path_startswith(path, *prefix)) + return true; + } + + /* no matches, so we should include this path only if we + * have no whitelist at all */ + return strv_length(include_prefixes) == 0; +} + static int parse_line(const char *fname, unsigned line, const char *buffer) { - Item *i, *existing; - char _cleanup_free_ + _cleanup_item_free_ Item *i = NULL; + Item *existing; + _cleanup_free_ char *mode = NULL, *user = NULL, *group = NULL, *age = NULL; char type; Hashmap *h; @@ -1046,8 +1065,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { &n); if (r < 2) { log_error("[%s:%u] Syntax error.", fname, line); - r = -EIO; - goto finish; + return -EIO; } if (n >= 0) { @@ -1077,16 +1095,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case CREATE_SYMLINK: if (!i->argument) { log_error("[%s:%u] Symlink file requires argument.", fname, line); - r = -EBADMSG; - goto finish; + return -EBADMSG; } break; case WRITE_FILE: if (!i->argument) { log_error("[%s:%u] Write file requires argument.", fname, line); - r = -EBADMSG; - goto finish; + return -EBADMSG; } break; @@ -1096,14 +1112,12 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { if (!i->argument) { log_error("[%s:%u] Device file requires argument.", fname, line); - r = -EBADMSG; - goto finish; + return -EBADMSG; } if (sscanf(i->argument, "%u:%u", &major, &minor) != 2) { log_error("[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i->argument); - r = -EBADMSG; - goto finish; + return -EBADMSG; } i->major_minor = makedev(major, minor); @@ -1112,24 +1126,20 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { default: log_error("[%s:%u] Unknown file type '%c'.", fname, line, type); - r = -EBADMSG; - goto finish; + return -EBADMSG; } i->type = type; if (!path_is_absolute(i->path)) { log_error("[%s:%u] Path '%s' not absolute.", fname, line, i->path); - r = -EBADMSG; - goto finish; + return -EBADMSG; } path_kill_slashes(i->path); - if (arg_prefix && !path_startswith(i->path, arg_prefix)) { - r = 0; - goto finish; - } + if (!should_include_path(i->path)) + return 0; if (user && !streq(user, "-")) { const char *u = user; @@ -1137,7 +1147,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); if (r < 0) { log_error("[%s:%u] Unknown user '%s'.", fname, line, user); - goto finish; + return r; } i->uid_set = true; @@ -1149,7 +1159,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { r = get_group_creds(&g, &i->gid); if (r < 0) { log_error("[%s:%u] Unknown group '%s'.", fname, line, group); - goto finish; + return r; } i->gid_set = true; @@ -1160,8 +1170,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { if (sscanf(mode, "%o", &m) != 1) { log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode); - r = -ENOENT; - goto finish; + return -ENOENT; } i->mode = m; @@ -1179,10 +1188,9 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { a++; } - if (parse_usec(a, &i->age) < 0) { + if (parse_sec(a, &i->age) < 0) { log_error("[%s:%u] Invalid age '%s'.", fname, line, age); - r = -EBADMSG; - goto finish; + return -EBADMSG; } i->age_set = true; @@ -1197,35 +1205,30 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { if (!item_equal(existing, i)) log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); - r = 0; - goto finish; + return 0; } r = hashmap_put(h, i->path, i); if (r < 0) { log_error("Failed to insert item %s: %s", i->path, strerror(-r)); - goto finish; + return r; } - i = NULL; - r = 0; - -finish: - if (i) - item_free(i); + i = NULL; /* avoid cleanup */ - return r; + return 0; } static int help(void) { printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" "Creates, deletes and cleans up volatile and temporary files and directories.\n\n" - " -h --help Show this help\n" - " --create Create marked files/directories\n" - " --clean Clean up marked directories\n" - " --remove Remove marked files/directories\n" - " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n", + " -h --help Show this help\n" + " --create Create marked files/directories\n" + " --clean Clean up marked directories\n" + " --remove Remove marked files/directories\n" + " --prefix=PATH Only apply rules that apply to paths with the specified prefix\n" + " --exclude-prefix=PATH Ignore rules that apply to paths with the specified prefix\n", program_invocation_short_name); return 0; @@ -1237,16 +1240,18 @@ static int parse_argv(int argc, char *argv[]) { ARG_CREATE, ARG_CLEAN, ARG_REMOVE, - ARG_PREFIX + ARG_PREFIX, + ARG_EXCLUDE_PREFIX, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "create", no_argument, NULL, ARG_CREATE }, - { "clean", no_argument, NULL, ARG_CLEAN }, - { "remove", no_argument, NULL, ARG_REMOVE }, - { "prefix", required_argument, NULL, ARG_PREFIX }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "create", no_argument, NULL, ARG_CREATE }, + { "clean", no_argument, NULL, ARG_CLEAN }, + { "remove", no_argument, NULL, ARG_REMOVE }, + { "prefix", required_argument, NULL, ARG_PREFIX }, + { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX }, + { NULL, 0, NULL, 0 } }; int c; @@ -1275,7 +1280,13 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_PREFIX: - arg_prefix = optarg; + if (strv_extend(&include_prefixes, optarg) < 0) + return log_oom(); + break; + + case ARG_EXCLUDE_PREFIX: + if (strv_extend(&exclude_prefixes, optarg) < 0) + return log_oom(); break; case '?': @@ -1440,6 +1451,8 @@ finish: hashmap_free(items); hashmap_free(globs); + strv_free(include_prefixes); + set_free_free(unix_sockets); label_finish();