X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Ftmpfiles%2Ftmpfiles.c;h=5d0f571bea605f7a15838e2dbf643309911418b0;hp=841d1635239e25a81fc596c99dadb594be013f4d;hb=54693d9bfa855841e8097d7a6b8c8d7acc068004;hpb=24f3a374b9588a6e409ba58b40bdd684050decf3 diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 841d16352..5d0f571be 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -38,15 +38,18 @@ #include #include #include +#include #include "log.h" #include "util.h" +#include "macro.h" #include "mkdir.h" #include "path-util.h" #include "strv.h" #include "label.h" #include "set.h" #include "conf-files.h" +#include "capability.h" /* 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 @@ -107,6 +110,9 @@ static const char * const conf_file_dirs[] = { "/run/tmpfiles.d", "/usr/local/lib/tmpfiles.d", "/usr/lib/tmpfiles.d", +#ifdef HAVE_SPLIT_USR + "/lib/tmpfiles.d", +#endif NULL }; @@ -257,8 +263,7 @@ static int dir_cleanup( sub_path = NULL; if (asprintf(&sub_path, "%s/%s", p, dent->d_name) < 0) { - log_error("Out of memory"); - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -469,7 +474,69 @@ static int item_set_perms(Item *i, const char *path) { return -errno; } - return label_fix(path, false); + return label_fix(path, false, false); +} + +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; + + if (fd < 0) { + if (i->type == WRITE_FILE && errno == ENOENT) + return 0; + + log_error("Failed to create file %s: %m", path); + return -errno; + } + + if (i->argument) { + ssize_t n; + size_t l; + _cleanup_free_ char *unescaped; + + unescaped = cunescape(i->argument); + if (unescaped == NULL) + return log_oom(); + + l = strlen(unescaped); + n = write(fd, unescaped, l); + + if (n < 0 || (size_t) n < l) { + log_error("Failed to write file %s: %s", path, n < 0 ? strerror(-n) : "Short write"); + close_nointr_nofail(fd); + return n < 0 ? n : -EIO; + } + } + + close_nointr_nofail(fd); + + if (stat(path, &st) < 0) { + log_error("stat(%s) failed: %m", path); + return -errno; + } + + if (!S_ISREG(st.st_mode)) { + log_error("%s is not a file.", path); + return -EEXIST; + } + + r = item_set_perms(i, path); + if (r < 0) + return r; + + return 0; } static int recursive_relabel_children(Item *i, const char *path) { @@ -605,74 +672,12 @@ static int create_item(Item *i) { case CREATE_FILE: case TRUNCATE_FILE: - case WRITE_FILE: { - int fd, flags; - - flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND : - i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0; - - u = umask(0); - label_context_set(i->path, S_IFREG); - fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode); - e = errno; - label_context_clear(); - umask(u); - errno = e; - - if (fd < 0) { - if (i->type == WRITE_FILE && errno == ENOENT) - break; - - log_error("Failed to create file %s: %m", i->path); - return -errno; - } - - if (i->argument) { - ssize_t n; - size_t l; - struct iovec iovec[2]; - static const char new_line = '\n'; - - l = strlen(i->argument); - - zero(iovec); - iovec[0].iov_base = i->argument; - iovec[0].iov_len = l; - - iovec[1].iov_base = (void*) &new_line; - iovec[1].iov_len = 1; - - n = writev(fd, iovec, 2); - - /* It's OK if we don't write the trailing - * newline, hence we check for l, instead of - * l+1 here. Files in /sys often refuse - * writing of the trailing newline. */ - if (n < 0 || (size_t) n < l) { - log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short write"); - close_nointr_nofail(fd); - return n < 0 ? n : -EIO; - } - } - - close_nointr_nofail(fd); - - if (stat(i->path, &st) < 0) { - log_error("stat(%s) failed: %m", i->path); - return -errno; - } - - if (!S_ISREG(st.st_mode)) { - log_error("%s is not a file.", i->path); - return -EEXIST; - } - - r = item_set_perms(i, i->path); + case WRITE_FILE: + r = glob_item(i, write_one_file); if (r < 0) return r; break; - } case TRUNCATE_DIRECTORY: case CREATE_DIRECTORY: @@ -762,7 +767,19 @@ static int create_item(Item *i) { case CREATE_BLOCK_DEVICE: case CREATE_CHAR_DEVICE: { - mode_t file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR); + mode_t file_type; + + if (have_effective_cap(CAP_MKNOD) == 0) { + /* In a container we lack CAP_MKNOD. We + shouldnt attempt to create the device node in + that case to avoid noise, and we don't support + virtualized devices in containers anyway. */ + + log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path); + return 0; + } + + file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR); u = umask(0); label_context_set(i->path, file_type); @@ -843,7 +860,9 @@ static int remove_item_instance(Item *i, const char *instance) { case TRUNCATE_DIRECTORY: case RECURSIVE_REMOVE_PATH: - r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, false); + /* FIXME: we probably should use dir_cleanup() here + * instead of rm_rf() so that 'x' is honoured. */ + r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false); if (r < 0 && r != -ENOENT) { log_error("rm_rf(%s): %s", instance, strerror(-r)); return r; @@ -964,10 +983,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { assert(buffer); i = new0(Item, 1); - if (!i) { - log_error("Out of memory"); - return -ENOMEM; - } + if (!i) + return log_oom(); if (sscanf(buffer, "%c " @@ -993,10 +1010,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { n += strspn(buffer+n, WHITESPACE); if (buffer[n] != 0 && (buffer[n] != '-' || buffer[n+1] != 0)) { i->argument = unquote(buffer+n, "\""); - if (!i->argument) { - log_error("Out of memory"); - return -ENOMEM; - } + if (!i->argument) + return log_oom(); } } @@ -1074,7 +1089,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { if (user && !streq(user, "-")) { const char *u = user; - r = get_user_creds(&u, &i->uid, NULL, NULL); + 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; @@ -1295,9 +1310,9 @@ static char *resolve_fragment(const char *fragment, const char **search_paths) { return strdup(fragment); STRV_FOREACH(p, search_paths) { - resolved_path = join(*p, "/", fragment, NULL); + resolved_path = strjoin(*p, "/", fragment, NULL); if (resolved_path == NULL) { - log_error("Out of memory"); + log_oom(); return NULL; } @@ -1332,7 +1347,7 @@ int main(int argc, char *argv[]) { globs = hashmap_new(string_hash_func, string_compare_func); if (!items || !globs) { - log_error("Out of memory"); + log_oom(); r = EXIT_FAILURE; goto finish; }