X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Ftmpfiles%2Ftmpfiles.c;h=0fd2bd233af5801b7c67bc108fbc666b0ee1b0e1;hb=45c196a76b2d883552c90807386d9bed40da822b;hp=c6121bccf3641fb25a43dc9fd79b4194fe00bcd5;hpb=1910cd0e05f7661986680e0a4472f4e857f90787;p=elogind.git diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index c6121bccf..0fd2bd233 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -99,6 +99,7 @@ typedef struct Item { bool gid_set:1; bool mode_set:1; bool age_set:1; + bool mask_perms:1; bool keep_first_level:1; @@ -449,35 +450,45 @@ finish: return r; } -static int item_set_perms_full(Item *i, const char *path, bool ignore_enoent) { +static int item_set_perms(Item *i, const char *path) { assert(i); assert(path); /* not using i->path directly because it may be a glob */ - if (i->mode_set) - if (chmod(path, i->mode) < 0) { - if (errno != ENOENT || !ignore_enoent) { - log_error("chmod(%s) failed: %m", path); - return -errno; + if (i->mode_set) { + mode_t m = i->mode; + + if (i->mask_perms) { + struct stat st; + + if (stat(path, &st) >= 0) { + if (!(st.st_mode & 0111)) + m &= ~0111; + if (!(st.st_mode & 0222)) + m &= ~0222; + if (!(st.st_mode & 0444)) + m &= ~0444; + if (!S_ISDIR(st.st_mode)) + m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ } } + if (chmod(path, m) < 0) { + log_error("chmod(%s) failed: %m", path); + return -errno; + } + } + if (i->uid_set || i->gid_set) if (chown(path, i->uid_set ? i->uid : (uid_t) -1, i->gid_set ? i->gid : (gid_t) -1) < 0) { - if (errno != ENOENT || !ignore_enoent) { - log_error("chown(%s) failed: %m", path); - return -errno; - } + log_error("chown(%s) failed: %m", path); + return -errno; } - return label_fix(path, ignore_enoent, false); -} - -static int item_set_perms(Item *i, const char *path) { - return item_set_perms_full(i, path, false); + return label_fix(path, false, false); } static int write_one_file(Item *i, const char *path) { @@ -708,9 +719,11 @@ static int create_item(Item *i) { case CREATE_FIFO: + label_context_set(i->path, S_IFIFO); RUN_WITH_UMASK(0000) { r = mkfifo(i->path, i->mode); } + label_context_clear(); if (r < 0 && errno != EEXIST) { log_error("Failed to create fifo %s: %m", i->path); @@ -781,9 +794,17 @@ static int create_item(Item *i) { label_context_clear(); } - if (r < 0 && errno != EEXIST) { - log_error("Failed to create device node %s: %m", i->path); - return -errno; + if (r < 0) { + if (errno == EPERM) { + log_debug("We lack permissions, possibly because of cgroup configuration; " + "skipping creation of device node %s.", i->path); + return 0; + } + + if (errno != EEXIST) { + log_error("Failed to create device node %s: %m", i->path); + return -errno; + } } if (stat(i->path, &st) < 0) { @@ -1010,7 +1031,9 @@ static int process_item(Item *i) { } static void item_free(Item *i) { - assert(i); + + if (!i) + return; free(i->path); free(i->argument); @@ -1064,15 +1087,13 @@ static bool item_equal(Item *a, Item *b) { static bool should_include_path(const char *path) { char **prefix; - STRV_FOREACH(prefix, arg_exclude_prefixes) { + STRV_FOREACH(prefix, arg_exclude_prefixes) if (path_startswith(path, *prefix)) return false; - } - STRV_FOREACH(prefix, arg_include_prefixes) { + STRV_FOREACH(prefix, arg_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 */ @@ -1141,7 +1162,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } } - switch(type) { + switch (type) { case CREATE_FILE: case TRUNCATE_FILE: @@ -1205,7 +1226,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } default: - log_error("[%s:%u] Unknown file type '%c'.", fname, line, type); + log_error("[%s:%u] Unknown command type '%c'.", fname, line, type); return -EBADMSG; } @@ -1257,9 +1278,15 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } if (mode && !streq(mode, "-")) { + const char *mm = mode; unsigned m; - if (sscanf(mode, "%o", &m) != 1) { + if (*mm == '~') { + i->mask_perms = true; + mm++; + } + + if (sscanf(mm, "%o", &m) != 1) { log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode); return -ENOENT; } @@ -1398,9 +1425,11 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: + free(arg_root); arg_root = path_make_absolute_cwd(optarg); if (!arg_root) return log_oom(); + path_kill_slashes(arg_root); break; @@ -1498,7 +1527,7 @@ int main(int argc, char *argv[]) { r = parse_argv(argc, argv); if (r <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + goto finish; log_set_target(LOG_TARGET_AUTO); log_parse_environment();