1
0
mirror of https://github.com/systemd/systemd.git synced 2025-08-25 13:49:55 +03:00

tmpfiles: generalize CreationMode and pass it everywhere

For some purposes we had CreationMode which indicates whether an inode
was created by us, or is pre-existing. Let's generalize that for *all*
operations. This is later useful to conditionalize certain operations on
that (and makes the codebase more systematic)
This commit is contained in:
Lennart Poettering
2022-09-11 12:21:58 +02:00
parent c5d554aa66
commit a9bc518c08

View File

@ -180,6 +180,14 @@ typedef enum DirectoryType {
_DIRECTORY_TYPE_MAX,
} DirectoryType;
typedef enum {
CREATION_NORMAL,
CREATION_EXISTING,
CREATION_FORCE,
_CREATION_MODE_MAX,
_CREATION_MODE_INVALID = -EINVAL,
} CreationMode;
static bool arg_cat_config = false;
static bool arg_user = false;
static OperationMask arg_operation = 0;
@ -205,6 +213,14 @@ STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
[CREATION_NORMAL] = "Created",
[CREATION_EXISTING] = "Found existing",
[CREATION_FORCE] = "Created replacement",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
int r;
@ -844,7 +860,13 @@ static mode_t process_mask_perms(mode_t mode, mode_t current) {
return mode;
}
static int fd_set_perms(Item *i, int fd, const char *path, const struct stat *st) {
static int fd_set_perms(
Item *i,
int fd,
const char *path,
const struct stat *st,
CreationMode creation) {
struct stat stbuf;
mode_t new_mode;
bool do_chown;
@ -979,7 +1001,11 @@ static int path_open_safe(const char *path) {
return fd;
}
static int path_set_perms(Item *i, const char *path) {
static int path_set_perms(
Item *i,
const char *path,
CreationMode creation) {
_cleanup_close_ int fd = -1;
assert(i);
@ -989,7 +1015,7 @@ static int path_set_perms(Item *i, const char *path) {
if (fd < 0)
return fd;
return fd_set_perms(i, fd, path, NULL);
return fd_set_perms(i, fd, path, /* st= */ NULL, creation);
}
static int parse_xattrs_from_arg(Item *i) {
@ -1028,7 +1054,13 @@ static int parse_xattrs_from_arg(Item *i) {
return 0;
}
static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *st) {
static int fd_set_xattrs(
Item *i,
int fd,
const char *path,
const struct stat *st,
CreationMode creation) {
assert(i);
assert(fd >= 0);
assert(path);
@ -1042,7 +1074,11 @@ static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *s
return 0;
}
static int path_set_xattrs(Item *i, const char *path) {
static int path_set_xattrs(
Item *i,
const char *path,
CreationMode creation) {
_cleanup_close_ int fd = -1;
assert(i);
@ -1052,7 +1088,7 @@ static int path_set_xattrs(Item *i, const char *path) {
if (fd < 0)
return fd;
return fd_set_xattrs(i, fd, path, NULL);
return fd_set_xattrs(i, fd, path, /* st = */ NULL, creation);
}
static int parse_acls_from_arg(Item *item) {
@ -1075,7 +1111,13 @@ static int parse_acls_from_arg(Item *item) {
}
#if HAVE_ACL
static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) {
static int path_set_acl(
const char *path,
const char *pretty,
acl_type_t type,
acl_t acl,
bool modify) {
_cleanup_(acl_free_charpp) char *t = NULL;
_cleanup_(acl_freep) acl_t dup = NULL;
int r;
@ -1124,7 +1166,13 @@ static int path_set_acl(const char *path, const char *pretty, acl_type_t type, a
}
#endif
static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *st) {
static int fd_set_acls(
Item *item,
int fd,
const char *path,
const struct stat *st,
CreationMode creation) {
int r = 0;
#if HAVE_ACL
struct stat stbuf;
@ -1174,7 +1222,7 @@ static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *
return r;
}
static int path_set_acls(Item *item, const char *path) {
static int path_set_acls(Item *item, const char *path, CreationMode creation) {
int r = 0;
#if HAVE_ACL
_cleanup_close_ int fd = -1;
@ -1186,7 +1234,7 @@ static int path_set_acls(Item *item, const char *path) {
if (fd < 0)
return fd;
r = fd_set_acls(item, fd, path, NULL);
r = fd_set_acls(item, fd, path, /* st= */ NULL, creation);
#endif
return r;
}
@ -1275,7 +1323,13 @@ static int parse_attribute_from_arg(Item *item) {
return 0;
}
static int fd_set_attribute(Item *item, int fd, const char *path, const struct stat *st) {
static int fd_set_attribute(
Item *item,
int fd,
const char *path,
const struct stat *st,
CreationMode creation) {
_cleanup_close_ int procfs_fd = -1;
struct stat stbuf;
unsigned f;
@ -1325,7 +1379,7 @@ static int fd_set_attribute(Item *item, int fd, const char *path, const struct s
return 0;
}
static int path_set_attribute(Item *item, const char *path) {
static int path_set_attribute(Item *item, const char *path, CreationMode creation) {
_cleanup_close_ int fd = -1;
if (!item->attribute_set || item->attribute_mask == 0)
@ -1335,7 +1389,7 @@ static int path_set_attribute(Item *item, const char *path) {
if (fd < 0)
return fd;
return fd_set_attribute(item, fd, path, NULL);
return fd_set_attribute(item, fd, path, /* st= */ NULL, creation);
}
static int write_argument_data(Item *i, int fd, const char *path) {
@ -1359,7 +1413,7 @@ static int write_argument_data(Item *i, int fd, const char *path) {
return 0;
}
static int write_one_file(Item *i, const char *path) {
static int write_one_file(Item *i, const char *path, CreationMode creation) {
_cleanup_close_ int fd = -1, dir_fd = -1;
_cleanup_free_ char *bn = NULL;
int r;
@ -1402,13 +1456,14 @@ static int write_one_file(Item *i, const char *path) {
if (r < 0)
return r;
return fd_set_perms(i, fd, path, NULL);
return fd_set_perms(i, fd, path, NULL, creation);
}
static int create_file(Item *i, const char *path) {
_cleanup_close_ int fd = -1, dir_fd = -1;
_cleanup_free_ char *bn = NULL;
struct stat stbuf, *st = NULL;
CreationMode creation;
int r = 0;
assert(i);
@ -1457,19 +1512,25 @@ static int create_file(Item *i, const char *path) {
path);
st = &stbuf;
} else if (item_binary_argument(i)) {
r = write_argument_data(i, fd, path);
if (r < 0)
return r;
creation = CREATION_EXISTING;
} else {
if (item_binary_argument(i)) {
r = write_argument_data(i, fd, path);
if (r < 0)
return r;
}
creation = CREATION_NORMAL;
}
return fd_set_perms(i, fd, path, st);
return fd_set_perms(i, fd, path, st, creation);
}
static int truncate_file(Item *i, const char *path) {
_cleanup_close_ int fd = -1, dir_fd = -1;
_cleanup_free_ char *bn = NULL;
struct stat stbuf, *st = NULL;
CreationMode creation;
bool erofs = false;
int r = 0;
@ -1493,10 +1554,16 @@ static int truncate_file(Item *i, const char *path) {
if (dir_fd < 0)
return dir_fd;
RUN_WITH_UMASK(0000) {
mac_selinux_create_file_prepare(path, S_IFREG);
fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
mac_selinux_create_file_clear();
creation = CREATION_EXISTING;
fd = RET_NERRNO(openat(dir_fd, bn, O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
if (fd == -ENOENT) {
creation = CREATION_NORMAL; /* Didn't work without O_CREATE, try again with */
RUN_WITH_UMASK(0000) {
mac_selinux_create_file_prepare(path, S_IFREG);
fd = RET_NERRNO(openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode));
mac_selinux_create_file_clear();
}
}
if (fd < 0) {
@ -1518,6 +1585,7 @@ static int truncate_file(Item *i, const char *path) {
}
erofs = true;
creation = CREATION_EXISTING;
}
if (fstat(fd, &stbuf) < 0)
@ -1544,7 +1612,7 @@ static int truncate_file(Item *i, const char *path) {
return r;
}
return fd_set_perms(i, fd, path, st);
return fd_set_perms(i, fd, path, st, creation);
}
static int copy_files(Item *i) {
@ -1597,36 +1665,22 @@ static int copy_files(Item *i) {
if (fd < 0)
return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
return fd_set_perms(i, fd, i->path, NULL);
return fd_set_perms(i, fd, i->path, /* st = */ NULL, _CREATION_MODE_INVALID);
}
typedef enum {
CREATION_NORMAL,
CREATION_EXISTING,
CREATION_FORCE,
_CREATION_MODE_MAX,
_CREATION_MODE_INVALID = -EINVAL,
} CreationMode;
static int create_directory_or_subvolume(
const char *path,
mode_t mode,
bool subvol,
CreationMode *ret_creation) {
static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
[CREATION_NORMAL] = "Created",
[CREATION_EXISTING] = "Found existing",
[CREATION_FORCE] = "Created replacement",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
static int create_directory_or_subvolume(const char *path, mode_t mode, bool subvol, CreationMode *creation) {
_cleanup_free_ char *bn = NULL;
_cleanup_close_ int pfd = -1;
CreationMode c;
int r;
int r, fd;
assert(path);
if (!creation)
creation = &c;
r = path_extract_filename(path, &bn);
if (r < 0)
return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
@ -1677,32 +1731,36 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub
return log_warning_errno(SYNTHETIC_ERRNO(EEXIST),
"\"%s\" already exists and is not a directory.", path);
*creation = CREATION_EXISTING;
c = CREATION_EXISTING;
} else
*creation = CREATION_NORMAL;
c = CREATION_NORMAL;
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(*creation), path);
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(c), path);
r = openat(pfd, bn, O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (r < 0)
fd = openat(pfd, bn, O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
return log_error_errno(errno, "Failed to open directory '%s': %m", bn);
return r;
if (ret_creation)
*ret_creation = c;
return fd;
}
static int create_directory(Item *i, const char *path) {
_cleanup_close_ int fd = -1;
CreationMode creation;
assert(i);
assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
fd = create_directory_or_subvolume(path, i->mode, false, NULL);
fd = create_directory_or_subvolume(path, i->mode, /* subvol= */ false, &creation);
if (fd == -EEXIST)
return 0;
if (fd < 0)
return fd;
return fd_set_perms(i, fd, path, NULL);
return fd_set_perms(i, fd, path, /* st= */ NULL, creation);
}
static int create_subvolume(Item *i, const char *path) {
@ -1713,7 +1771,7 @@ static int create_subvolume(Item *i, const char *path) {
assert(i);
assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
fd = create_directory_or_subvolume(path, i->mode, true, &creation);
fd = create_directory_or_subvolume(path, i->mode, /* subvol = */ true, &creation);
if (fd == -EEXIST)
return 0;
if (fd < 0)
@ -1736,14 +1794,14 @@ static int create_subvolume(Item *i, const char *path) {
log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
}
r = fd_set_perms(i, fd, path, NULL);
r = fd_set_perms(i, fd, path, /* st= */ NULL, creation);
if (q < 0) /* prefer the quota change error from above */
return q;
return r;
}
static int empty_directory(Item *i, const char *path) {
static int empty_directory(Item *i, const char *path, CreationMode creation) {
int r;
assert(i);
@ -1763,7 +1821,7 @@ static int empty_directory(Item *i, const char *path) {
return 0;
}
return path_set_perms(i, path);
return path_set_perms(i, path, creation);
}
static int create_device(Item *i, mode_t file_type) {
@ -1841,7 +1899,7 @@ static int create_device(Item *i, mode_t file_type) {
if (fd < 0)
return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
return fd_set_perms(i, fd, i->path, NULL);
return fd_set_perms(i, fd, i->path, /* st = */ NULL, creation);
}
static int create_fifo(Item *i, const char *path) {
@ -1901,13 +1959,19 @@ static int create_fifo(Item *i, const char *path) {
if (fd < 0)
return log_error_errno(errno, "Failed to openat(%s): %m", path);
return fd_set_perms(i, fd, i->path, NULL);
return fd_set_perms(i, fd, i->path, /* st = */ NULL, creation);
}
typedef int (*action_t)(Item *i, const char *path);
typedef int (*fdaction_t)(Item *i, int fd, const char *path, const struct stat *st);
typedef int (*action_t)(Item *i, const char *path, CreationMode creation);
typedef int (*fdaction_t)(Item *i, int fd, const char *path, const struct stat *st, CreationMode creation);
static int item_do(
Item *i,
int fd,
const char *path,
CreationMode creation,
fdaction_t action) {
static int item_do(Item *i, int fd, const char *path, fdaction_t action) {
struct stat st;
int r = 0, q;
@ -1920,9 +1984,8 @@ static int item_do(Item *i, int fd, const char *path, fdaction_t action) {
goto finish;
}
/* This returns the first error we run into, but nevertheless
* tries to go on */
r = action(i, fd, path, &st);
/* This returns the first error we run into, but nevertheless tries to go on */
r = action(i, fd, path, &st, creation);
if (S_ISDIR(st.st_mode)) {
_cleanup_closedir_ DIR *d = NULL;
@ -1954,7 +2017,7 @@ static int item_do(Item *i, int fd, const char *path, fdaction_t action) {
q = log_oom();
else
/* Pass ownership of dirent fd over */
q = item_do(i, de_fd, de_path, action);
q = item_do(i, de_fd, de_path, CREATION_EXISTING, action);
}
if (q < 0 && r == 0)
@ -1977,7 +2040,8 @@ static int glob_item(Item *i, action_t action) {
return log_error_errno(k, "glob(%s) failed: %m", i->path);
STRV_FOREACH(fn, g.gl_pathv) {
k = action(i, *fn);
/* We pass CREATION_EXISTING here, since if we are globbing for it, it always has to exist */
k = action(i, *fn, CREATION_EXISTING);
if (k < 0 && r == 0)
r = k;
}
@ -2011,7 +2075,7 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
continue;
}
k = item_do(i, fd, *fn, action);
k = item_do(i, fd, *fn, CREATION_EXISTING, action);
if (k < 0 && r == 0)
r = k;
@ -2404,7 +2468,7 @@ static int create_item(Item *i) {
return 0;
}
static int remove_item_instance(Item *i, const char *instance) {
static int remove_item_instance(Item *i, const char *instance, CreationMode creation) {
int r;
assert(i);
@ -2477,7 +2541,11 @@ static char *age_by_to_string(AgeBy ab, bool is_dir) {
return ret;
}
static int clean_item_instance(Item *i, const char* instance) {
static int clean_item_instance(
Item *i,
const char* instance,
CreationMode creation) {
_cleanup_closedir_ DIR *d = NULL;
STRUCT_STATX_DEFINE(sx);
int mountpoint, r;
@ -2562,7 +2630,7 @@ static int clean_item(Item *i) {
case TRUNCATE_DIRECTORY:
case IGNORE_PATH:
case COPY_FILES:
clean_item_instance(i, i->path);
clean_item_instance(i, i->path, CREATION_EXISTING);
return 0;
case EMPTY_DIRECTORY:
case IGNORE_DIRECTORY_PATH: