X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Ftmpfiles%2Ftmpfiles.c;h=b830850879b951c80d9f4f5bec20432b533ea002;hb=d7b8eec7dc7fe307d3a08b32cf1a9ad4276ce6d5;hp=d60c57793b12872365b0c6ab234990889d7be1d4;hpb=fed1e721fd0c81e60c77120539f34e16c2585634;p=elogind.git diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index d60c57793..b83085087 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "log.h" #include "util.h" @@ -54,6 +54,8 @@ #include "specifier.h" #include "build.h" #include "copy.h" +#include "selinux-util.h" +#include "btrfs-util.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 @@ -66,11 +68,13 @@ typedef enum ItemType { TRUNCATE_FILE = 'F', CREATE_DIRECTORY = 'd', TRUNCATE_DIRECTORY = 'D', + CREATE_SUBVOLUME = 'v', CREATE_FIFO = 'p', CREATE_SYMLINK = 'L', CREATE_CHAR_DEVICE = 'c', CREATE_BLOCK_DEVICE = 'b', COPY_FILES = 'C', + SET_XATTR = 't', /* These ones take globs */ WRITE_FILE = 'w', @@ -88,6 +92,7 @@ typedef struct Item { char *path; char *argument; + char **xattrs; uid_t uid; gid_t gid; mode_t mode; @@ -487,6 +492,67 @@ static int item_set_perms(Item *i, const char *path) { return label_fix(path, false, false); } +static int get_xattrs_from_arg(Item *i) { + char *xattr; + const char *p; + int r; + + assert(i); + + if (!i->argument) { + log_error("%s: Argument can't be empty!", i->path); + return -EBADMSG; + } + p = i->argument; + + while ((r = unquote_first_word(&p, &xattr, false)) > 0) { + _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL; + r = split_pair(xattr, "=", &name, &value); + if (r < 0) { + log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr); + free(xattr); + continue; + } + free(xattr); + if (streq(name, "") || streq(value, "")) { + log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value); + continue; + } + tmp = unquote(value, "\""); + if (!tmp) + return log_oom(); + free(value); + value = cunescape(tmp); + if (!value) + return log_oom(); + if (strv_consume_pair(&i->xattrs, name, value) < 0) + return log_oom(); + name = value = NULL; + } + + return r; +} + +static int item_set_xattrs(Item *i, const char *path) { + char **name, **value; + + assert(i); + assert(path); + + if (strv_isempty(i->xattrs)) + return 0; + + STRV_FOREACH_PAIR(name, value, i->xattrs) { + int n; + n = strlen(*value); + if (lsetxattr(path, *name, *value, n, 0) < 0) { + log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path); + return -errno; + } + } + return 0; +} + static int write_one_file(Item *i, const char *path) { _cleanup_close_ int fd = -1; int flags, r = 0; @@ -544,6 +610,10 @@ static int write_one_file(Item *i, const char *path) { if (r < 0) return r; + r = item_set_xattrs(i, i->path); + if (r < 0) + return r; + return 0; } @@ -691,17 +761,27 @@ static int create_item(Item *i) { break; - case TRUNCATE_DIRECTORY: case CREATE_DIRECTORY: + case TRUNCATE_DIRECTORY: + case CREATE_SUBVOLUME: - RUN_WITH_UMASK(0000) { + RUN_WITH_UMASK(0000) mkdir_parents_label(i->path, 0755); - r = mkdir_label(i->path, i->mode); + + if (i->type == CREATE_SUBVOLUME) { + RUN_WITH_UMASK((~i->mode) & 0777) + r = btrfs_subvol_make(i->path); + } else + r = 0; + + if (i->type == CREATE_DIRECTORY || r == -ENOTTY) { + RUN_WITH_UMASK(0000) + r = mkdir_label(i->path, i->mode); } if (r < 0) { if (r != -EEXIST) - return log_error_errno(r, "Failed to create directory %s: %m", i->path); + return log_error_errno(r, "Failed to create directory or subvolume %s: %m", i->path); if (stat(i->path, &st) < 0) return log_error_errno(errno, "stat(%s) failed: %m", i->path); @@ -716,6 +796,10 @@ static int create_item(Item *i) { if (r < 0) return r; + r = item_set_xattrs(i, i->path); + if (r < 0) + return r; + break; case CREATE_FIFO: @@ -756,6 +840,10 @@ static int create_item(Item *i) { if (r < 0) return r; + r = item_set_xattrs(i, i->path); + if (r < 0) + return r; + break; case CREATE_SYMLINK: @@ -787,6 +875,10 @@ static int create_item(Item *i) { } } + r = item_set_xattrs(i, i->path); + if (r < 0) + return r; + break; case CREATE_BLOCK_DEVICE: @@ -847,6 +939,10 @@ static int create_item(Item *i) { if (r < 0) return r; + r = item_set_xattrs(i, i->path); + if (r < 0) + return r; + break; } @@ -863,7 +959,12 @@ static int create_item(Item *i) { r = glob_item(i, item_set_perms_recursive); if (r < 0) return r; + break; + case SET_XATTR: + r = item_set_xattrs(i, i->path); + if (r < 0) + return r; break; } @@ -882,6 +983,7 @@ static int remove_item_instance(Item *i, const char *instance) { case CREATE_FILE: case TRUNCATE_FILE: case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: case CREATE_FIFO: case CREATE_SYMLINK: case CREATE_BLOCK_DEVICE: @@ -893,6 +995,7 @@ static int remove_item_instance(Item *i, const char *instance) { case RECURSIVE_RELABEL_PATH: case WRITE_FILE: case COPY_FILES: + case SET_XATTR: break; case REMOVE_PATH: @@ -925,6 +1028,7 @@ static int remove_item(Item *i) { case CREATE_FILE: case TRUNCATE_FILE: case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: case CREATE_FIFO: case CREATE_SYMLINK: case CREATE_CHAR_DEVICE: @@ -936,6 +1040,7 @@ static int remove_item(Item *i) { case RECURSIVE_RELABEL_PATH: case WRITE_FILE: case COPY_FILES: + case SET_XATTR: break; case REMOVE_PATH: @@ -1001,6 +1106,7 @@ static int clean_item(Item *i) { switch (i->type) { case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: case TRUNCATE_DIRECTORY: case IGNORE_PATH: case COPY_FILES: @@ -1059,6 +1165,7 @@ static void item_free(Item *i) { free(i->path); free(i->argument); + strv_free(i->xattrs); free(i); } @@ -1198,6 +1305,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case CREATE_FILE: case TRUNCATE_FILE: case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: case TRUNCATE_DIRECTORY: case CREATE_FIFO: case IGNORE_PATH: @@ -1257,6 +1365,16 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { break; } + case SET_XATTR: + if (!i->argument) { + log_error("[%s:%u] Set extended attribute requires argument.", fname, line); + return -EBADMSG; + } + r = get_xattrs_from_arg(i); + if (r < 0) + return r; + break; + default: log_error("[%s:%u] Unknown command type '%c'.", fname, line, type); return -EBADMSG; @@ -1328,6 +1446,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } else i->mode = i->type == CREATE_DIRECTORY || + i->type == CREATE_SUBVOLUME || i->type == TRUNCATE_DIRECTORY ? 0755 : 0644; if (age && !streq(age, "-")) { @@ -1350,18 +1469,35 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { existing = hashmap_get(h, i->path); if (existing) { - - /* Two identical items are fine */ - if (!item_equal(existing, i)) - log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); - - return 0; + if (i->type == SET_XATTR) { + r = strv_extend_strv(&existing->xattrs, i->xattrs); + if (r < 0) + return log_oom(); + return 0; + } else if (existing->type == SET_XATTR) { + r = strv_extend_strv(&i->xattrs, existing->xattrs); + if (r < 0) + return log_oom(); + r = hashmap_replace(h, i->path, i); + if (r < 0) { + log_error("Failed to replace item for %s.", i->path); + return r; + } + item_free(existing); + } else { + /* Two identical items are fine */ + if (!item_equal(existing, i)) + log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); + return 0; + } + } else { + r = hashmap_put(h, i->path, i); + if (r < 0) { + log_error("Failed to insert item %s: %s", i->path, strerror(-r)); + return r; + } } - r = hashmap_put(h, i->path, i); - if (r < 0) - return log_error_errno(r, "Failed to insert item %s: %m", i->path); - i = NULL; /* avoid cleanup */ return 0; @@ -1518,7 +1654,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { continue; HASHMAP_FOREACH(j, items, iter) { - if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY) + if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME) continue; if (path_equal(j->path, i->path)) {