preparatory work from the OCI PR (#40149)
This adds 11 commits with minor preparatory commits for PR #39621. That PR has tests that cover all this, even if this one doesn't, but the bits added here are relatively minor.
This commit is contained in:
+34
-24
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dirent-util.h"
|
||||
@@ -433,30 +434,25 @@ int recurse_dir(
|
||||
i,
|
||||
statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */
|
||||
userdata);
|
||||
if (r == RECURSE_DIR_LEAVE_DIRECTORY)
|
||||
break;
|
||||
if (r == RECURSE_DIR_SKIP_ENTRY)
|
||||
continue;
|
||||
if (r != RECURSE_DIR_CONTINUE)
|
||||
return r;
|
||||
if (r == RECURSE_DIR_CONTINUE) {
|
||||
r = recurse_dir(subdir_fd,
|
||||
p,
|
||||
statx_mask,
|
||||
n_depth_max - 1,
|
||||
flags & ~RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */
|
||||
func,
|
||||
userdata);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = recurse_dir(subdir_fd,
|
||||
p,
|
||||
statx_mask,
|
||||
n_depth_max - 1,
|
||||
flags & ~RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */
|
||||
func,
|
||||
userdata);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = func(RECURSE_DIR_LEAVE,
|
||||
p,
|
||||
dir_fd,
|
||||
subdir_fd,
|
||||
i,
|
||||
statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */
|
||||
userdata);
|
||||
r = func(RECURSE_DIR_LEAVE,
|
||||
p,
|
||||
dir_fd,
|
||||
subdir_fd,
|
||||
i,
|
||||
statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */
|
||||
userdata);
|
||||
}
|
||||
} else
|
||||
/* Non-directory inode */
|
||||
r = func(RECURSE_DIR_ENTRY,
|
||||
@@ -469,7 +465,21 @@ int recurse_dir(
|
||||
|
||||
if (r == RECURSE_DIR_LEAVE_DIRECTORY)
|
||||
break;
|
||||
if (!IN_SET(r, RECURSE_DIR_SKIP_ENTRY, RECURSE_DIR_CONTINUE))
|
||||
|
||||
if (IN_SET(r, RECURSE_DIR_UNLINK, RECURSE_DIR_UNLINK_GRACEFUL)) {
|
||||
int f = subdir_fd >= 0 ? AT_REMOVEDIR : 0;
|
||||
|
||||
/* Close inodes before we try to delete them */
|
||||
subdir_fd = safe_close(subdir_fd);
|
||||
inode_fd = safe_close(inode_fd);
|
||||
|
||||
if (unlinkat(dir_fd, i->d_name, f) < 0) {
|
||||
if (r != RECURSE_DIR_UNLINK_GRACEFUL)
|
||||
return -errno;
|
||||
|
||||
log_debug_errno(errno, "Unable to remove '%s', ignoring: %m", p);
|
||||
}
|
||||
} else if (!IN_SET(r, RECURSE_DIR_SKIP_ENTRY, RECURSE_DIR_CONTINUE))
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ typedef enum RecurseDirEvent {
|
||||
#define RECURSE_DIR_CONTINUE 0
|
||||
#define RECURSE_DIR_LEAVE_DIRECTORY INT_MIN
|
||||
#define RECURSE_DIR_SKIP_ENTRY (INT_MIN+1)
|
||||
#define RECURSE_DIR_UNLINK (INT_MIN+2)
|
||||
#define RECURSE_DIR_UNLINK_GRACEFUL (INT_MIN+3)
|
||||
|
||||
/* Make sure that the negative errno range and these two special returns don't overlap */
|
||||
assert_cc(RECURSE_DIR_LEAVE_DIRECTORY < -ERRNO_MAX);
|
||||
|
||||
@@ -31,6 +31,15 @@ static inline void iovec_done(struct iovec *iovec) {
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline void iovec_done_many_and_free(struct iovec *iovec, size_t n) {
|
||||
if (n > 0) {
|
||||
assert(iovec);
|
||||
FOREACH_ARRAY(j, iovec, n)
|
||||
iovec_done(j);
|
||||
}
|
||||
free(iovec);
|
||||
}
|
||||
|
||||
static inline bool iovec_is_set(const struct iovec *iovec) {
|
||||
/* Checks if the iovec points to a non-empty chunk of memory */
|
||||
return iovec && iovec->iov_len > 0 && iovec->iov_base;
|
||||
|
||||
@@ -257,7 +257,7 @@ static int tar_import_fork_tar(TarImport *i) {
|
||||
return r;
|
||||
|
||||
_cleanup_close_ int directory_fd = -EBADF;
|
||||
r = mountfsd_make_directory(d, /* flags= */ 0, &directory_fd);
|
||||
r = mountfsd_make_directory(d, MODE_INVALID, /* flags= */ 0, &directory_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ static int tar_pull_make_local_copy(TarPull *p) {
|
||||
}
|
||||
|
||||
_cleanup_close_ int directory_fd = -EBADF;
|
||||
r = mountfsd_make_directory(t, /* flags= */ 0, &directory_fd);
|
||||
r = mountfsd_make_directory(t, MODE_INVALID, /* flags= */ 0, &directory_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -609,7 +609,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
||||
return r;
|
||||
|
||||
_cleanup_close_ int directory_fd = -EBADF;
|
||||
r = mountfsd_make_directory(where, /* flags= */ 0, &directory_fd);
|
||||
r = mountfsd_make_directory(where, MODE_INVALID, /* flags= */ 0, &directory_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -701,3 +701,45 @@ int json_variant_new_fd_info(sd_json_variant **ret, int fd) {
|
||||
JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE("mountId", mntid),
|
||||
SD_JSON_BUILD_PAIR_VARIANT("fileHandle", w));
|
||||
}
|
||||
|
||||
int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
mode_t *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*m = MODE_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Let the SD_JSON_STRICT determine if we allow suid/sgid/sticky or not */
|
||||
mode_t limit = FLAGS_SET(flags, SD_JSON_STRICT) ? 0777 : 07777;
|
||||
|
||||
if (sd_json_variant_is_string(variant)) {
|
||||
/* NB: we parse the mode in the usual octal if a string is specified. */
|
||||
|
||||
mode_t mode;
|
||||
r = parse_mode(sd_json_variant_string(variant), &mode);
|
||||
if (r < 0)
|
||||
return json_log(variant, flags, r, "JSON field '%s' is not a valid access mode string.", strna(name));
|
||||
|
||||
if (mode > limit)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
|
||||
"JSON field '%s' outside of valid range 0%s0%o.",
|
||||
strna(name), glyph(GLYPH_ELLIPSIS), limit);
|
||||
|
||||
*m = mode;
|
||||
|
||||
} else if (sd_json_variant_is_unsigned(variant)) {
|
||||
|
||||
uint64_t k = sd_json_variant_unsigned(variant);
|
||||
if (k > (uint64_t) limit)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
|
||||
"JSON field '%s' outside of valid range 0%s0%o.",
|
||||
strna(name), glyph(GLYPH_ELLIPSIS), limit);
|
||||
|
||||
*m = (mode_t) k;
|
||||
} else
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is neither a number nor a string.", strna(name));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ int json_dispatch_devnum(const char *name, sd_json_variant *variant, sd_json_dis
|
||||
int json_dispatch_ifindex(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_log_level(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
|
||||
static inline int json_variant_unbase64_iovec(sd_json_variant *v, struct iovec *ret) {
|
||||
return sd_json_variant_unbase64(v, ret ? &ret->iov_base : NULL, ret ? &ret->iov_len : NULL);
|
||||
|
||||
@@ -124,7 +124,7 @@ static int validate_image_fd(int fd, MountImageParameters *p) {
|
||||
return r;
|
||||
}
|
||||
|
||||
fl = fd_verify_safe_flags(fd);
|
||||
fl = fd_verify_safe_flags_full(fd, O_NONBLOCK);
|
||||
if (fl < 0)
|
||||
return log_debug_errno(fl, "Image file descriptor has unsafe flags set: %m");
|
||||
|
||||
@@ -353,6 +353,8 @@ static int vl_method_mount_image(
|
||||
}
|
||||
|
||||
r = validate_image_fd(image_fd, &p);
|
||||
if (r == -EREMOTEIO)
|
||||
return sd_varlink_errorbo(link, "io.systemd.MountFileSystem.BadFileDescriptorFlags", SD_JSON_BUILD_PAIR_STRING("parameter", "imageFileDescriptor"));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1003,6 +1005,7 @@ static int vl_method_mount_directory(
|
||||
typedef struct MakeDirectoryParameters {
|
||||
unsigned parent_fd_idx;
|
||||
const char *name;
|
||||
mode_t mode;
|
||||
} MakeDirectoryParameters;
|
||||
|
||||
static int vl_method_make_directory(
|
||||
@@ -1012,14 +1015,16 @@ static int vl_method_make_directory(
|
||||
void *userdata) {
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "parentFileDescriptor", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(MakeDirectoryParameters, parent_fd_idx), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, json_dispatch_const_filename, offsetof(MakeDirectoryParameters, name), SD_JSON_MANDATORY },
|
||||
{ "parentFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(MakeDirectoryParameters, parent_fd_idx), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, json_dispatch_const_filename, offsetof(MakeDirectoryParameters, name), SD_JSON_MANDATORY },
|
||||
{ "mode", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, offsetof(MakeDirectoryParameters, mode), SD_JSON_STRICT },
|
||||
VARLINK_DISPATCH_POLKIT_FIELD,
|
||||
{}
|
||||
};
|
||||
|
||||
MakeDirectoryParameters p = {
|
||||
.parent_fd_idx = UINT_MAX,
|
||||
.mode = MODE_INVALID,
|
||||
};
|
||||
Hashmap **polkit_registry = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
@@ -1028,6 +1033,11 @@ static int vl_method_make_directory(
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (p.mode == MODE_INVALID)
|
||||
p.mode = 0700;
|
||||
else
|
||||
p.mode &= 0775; /* refuse generating world writable dirs */
|
||||
|
||||
if (p.parent_fd_idx == UINT_MAX)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "parentFileDescriptor");
|
||||
|
||||
@@ -1089,11 +1099,11 @@ static int vl_method_make_directory(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_close_ int fd = open_mkdir_at(parent_fd, t, O_CLOEXEC, 0700);
|
||||
_cleanup_close_ int fd = open_mkdir_at(parent_fd, t, O_CLOEXEC, p.mode);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
r = RET_NERRNO(fchmod(fd, 0700)); /* Set mode explicitly, as paranoia regarding umask games */
|
||||
r = RET_NERRNO(fchmod(fd, p.mode)); /* Set mode explicitly, as paranoia regarding umask games */
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
@@ -1491,6 +1491,7 @@ static int unpriviled_clone(Image *i, const char *new_path) {
|
||||
_cleanup_close_ int new_fd = -EBADF;
|
||||
r = mountfsd_make_directory(
|
||||
new_path,
|
||||
MODE_INVALID,
|
||||
/* flags= */ 0,
|
||||
&new_fd);
|
||||
if (r < 0)
|
||||
|
||||
+76
-22
@@ -630,7 +630,35 @@ static void check_partition_flags(
|
||||
log_debug("Unexpected partition flag %llu set on %s!", bit, node);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int make_image_name(const char *path, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_free_ char *filename = NULL;
|
||||
r = path_extract_filename(path, &filename);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_free_ char *name = NULL;
|
||||
r = raw_strip_suffixes(filename, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(name)) {
|
||||
log_debug("Image name %s is not valid, ignoring.", strna(name));
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if HAVE_BLKID
|
||||
static int dissected_image_new(const char *path, DissectedImage **ret) {
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
||||
_cleanup_free_ char *name = NULL;
|
||||
@@ -639,20 +667,9 @@ static int dissected_image_new(const char *path, DissectedImage **ret) {
|
||||
assert(ret);
|
||||
|
||||
if (path) {
|
||||
_cleanup_free_ char *filename = NULL;
|
||||
|
||||
r = path_extract_filename(path, &filename);
|
||||
r = make_image_name(path, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = raw_strip_suffixes(filename, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(name)) {
|
||||
log_debug("Image name %s is not valid, ignoring.", strna(name));
|
||||
name = mfree(name);
|
||||
}
|
||||
}
|
||||
|
||||
m = new(DissectedImage, 1);
|
||||
@@ -5022,8 +5039,8 @@ static void mount_image_reply_parameters_done(MountImageReplyParameters *p) {
|
||||
|
||||
#endif
|
||||
|
||||
int mountfsd_mount_image(
|
||||
const char *path,
|
||||
int mountfsd_mount_image_fd(
|
||||
int image_fd,
|
||||
int userns_fd,
|
||||
const ImagePolicy *image_policy,
|
||||
const VeritySettings *verity,
|
||||
@@ -5043,13 +5060,13 @@ int mountfsd_mount_image(
|
||||
};
|
||||
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *di = NULL;
|
||||
_cleanup_close_ int image_fd = -EBADF, verity_data_fd = -EBADF;
|
||||
_cleanup_close_ int verity_data_fd = -EBADF;
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
_cleanup_free_ char *ps = NULL;
|
||||
const char *error_id;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(image_fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.MountFileSystem");
|
||||
@@ -5064,9 +5081,11 @@ int mountfsd_mount_image(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable varlink fd passing for write: %m");
|
||||
|
||||
image_fd = open(path, O_RDONLY|O_CLOEXEC);
|
||||
_cleanup_close_ int reopened_fd = -EBADF;
|
||||
|
||||
image_fd = fd_reopen_condition(image_fd, O_CLOEXEC|O_NOCTTY|O_NONBLOCK|(FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_READ_ONLY) ? O_RDONLY : O_RDWR), O_PATH, &reopened_fd);
|
||||
if (image_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||
return log_error_errno(image_fd, "Failed to reopen fd: %m");
|
||||
|
||||
r = sd_varlink_push_dup_fd(vl, image_fd);
|
||||
if (r < 0)
|
||||
@@ -5159,7 +5178,7 @@ int mountfsd_mount_image(
|
||||
assert(pp.designator >= 0);
|
||||
|
||||
if (!di) {
|
||||
r = dissected_image_new(path, &di);
|
||||
r = dissected_image_new(/* path= */ NULL, &di);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocated new dissected image structure: %m");
|
||||
}
|
||||
@@ -5194,6 +5213,38 @@ int mountfsd_mount_image(
|
||||
#endif
|
||||
}
|
||||
|
||||
int mountfsd_mount_image(
|
||||
const char *path,
|
||||
int userns_fd,
|
||||
const ImagePolicy *image_policy,
|
||||
const VeritySettings *verity,
|
||||
DissectImageFlags flags,
|
||||
DissectedImage **ret) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_close_ int image_fd = open(path, O_RDONLY|O_CLOEXEC);
|
||||
if (image_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *di = NULL;
|
||||
r = mountfsd_mount_image_fd(image_fd, userns_fd, image_policy, verity, flags, &di);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!di->image_name) {
|
||||
r = make_image_name(path, &di->image_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(di);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mountfsd_mount_directory_fd(
|
||||
int directory_fd,
|
||||
int userns_fd,
|
||||
@@ -5284,6 +5335,7 @@ int mountfsd_mount_directory(
|
||||
int mountfsd_make_directory_fd(
|
||||
int parent_fd,
|
||||
const char *name,
|
||||
mode_t mode,
|
||||
DissectImageFlags flags,
|
||||
int *ret_directory_fd) {
|
||||
|
||||
@@ -5291,7 +5343,6 @@ int mountfsd_make_directory_fd(
|
||||
|
||||
assert(parent_fd >= 0);
|
||||
assert(name);
|
||||
assert(ret_directory_fd);
|
||||
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.MountFileSystem");
|
||||
@@ -5319,6 +5370,7 @@ int mountfsd_make_directory_fd(
|
||||
&error_id,
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("parentFileDescriptor", 0),
|
||||
SD_JSON_BUILD_PAIR_STRING("name", name),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!IN_SET(mode, MODE_INVALID, 0700), "mode", SD_JSON_BUILD_UNSIGNED(mode)), /* suppress this field if default/unset */
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5337,12 +5389,14 @@ int mountfsd_make_directory_fd(
|
||||
if (directory_fd < 0)
|
||||
return log_error_errno(directory_fd, "Failed to take directory fd from Varlink connection: %m");
|
||||
|
||||
*ret_directory_fd = TAKE_FD(directory_fd);
|
||||
if (ret_directory_fd)
|
||||
*ret_directory_fd = TAKE_FD(directory_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mountfsd_make_directory(
|
||||
const char *path,
|
||||
mode_t mode,
|
||||
DissectImageFlags flags,
|
||||
int *ret_directory_fd) {
|
||||
|
||||
@@ -5362,5 +5416,5 @@ int mountfsd_make_directory(
|
||||
if (fd < 0)
|
||||
return log_error_errno(r, "Failed to open '%s': %m", parent);
|
||||
|
||||
return mountfsd_make_directory_fd(fd, dirname, flags, ret_directory_fd);
|
||||
return mountfsd_make_directory_fd(fd, dirname, mode, flags, ret_directory_fd);
|
||||
}
|
||||
|
||||
@@ -268,9 +268,10 @@ static inline const char* dissected_partition_fstype(const DissectedPartition *m
|
||||
|
||||
int get_common_dissect_directory(char **ret);
|
||||
|
||||
int mountfsd_mount_image_fd(int image_fd, int userns_fd, const ImagePolicy *image_policy, const VeritySettings *verity, DissectImageFlags flags, DissectedImage **ret);
|
||||
int mountfsd_mount_image(const char *path, int userns_fd, const ImagePolicy *image_policy, const VeritySettings *verity, DissectImageFlags flags, DissectedImage **ret);
|
||||
int mountfsd_mount_directory_fd(int directory_fd, int userns_fd, DissectImageFlags flags, int *ret_mount_fd);
|
||||
int mountfsd_mount_directory(const char *path, int userns_fd, DissectImageFlags flags, int *ret_mount_fd);
|
||||
|
||||
int mountfsd_make_directory_fd(int parent_fd, const char *name, DissectImageFlags flags, int *ret_directory_fd);
|
||||
int mountfsd_make_directory(const char *path, DissectImageFlags flags, int *ret_directory_fd);
|
||||
int mountfsd_make_directory_fd(int parent_fd, const char *name, mode_t mode, DissectImageFlags flags, int *ret_directory_fd);
|
||||
int mountfsd_make_directory(const char *path, mode_t mode, DissectImageFlags flags, int *ret_directory_fd);
|
||||
|
||||
@@ -462,50 +462,6 @@ static int json_dispatch_image_path(const char *name, sd_json_variant *variant,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_dispatch_umask(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
mode_t *m = userdata;
|
||||
uint64_t k;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*m = MODE_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_unsigned(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a number.", strna(name));
|
||||
|
||||
k = sd_json_variant_unsigned(variant);
|
||||
if (k > 0777)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
"JSON field '%s' outside of valid range 0%s0777.",
|
||||
strna(name), glyph(GLYPH_ELLIPSIS));
|
||||
|
||||
*m = (mode_t) k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
mode_t *m = userdata;
|
||||
uint64_t k;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*m = MODE_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_unsigned(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a number.", strna(name));
|
||||
|
||||
k = sd_json_variant_unsigned(variant);
|
||||
if (k > 07777)
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
"JSON field '%s' outside of valid range 0%s07777.",
|
||||
strna(name), glyph(GLYPH_ELLIPSIS));
|
||||
|
||||
*m = (mode_t) k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_dispatch_locale(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
char **s = userdata;
|
||||
const char *n;
|
||||
@@ -1273,7 +1229,7 @@ static int dispatch_per_machine(const char *name, sd_json_variant *variant, sd_j
|
||||
{ "iconName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(UserRecord, icon_name), SD_JSON_STRICT },
|
||||
{ "location", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(UserRecord, location), 0 },
|
||||
{ "shell", SD_JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
|
||||
{ "umask", SD_JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
|
||||
{ "umask", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, offsetof(UserRecord, umask), SD_JSON_STRICT },
|
||||
{ "environment", SD_JSON_VARIANT_ARRAY, json_dispatch_strv_environment, offsetof(UserRecord, environment), 0 },
|
||||
{ "timeZone", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(UserRecord, time_zone), SD_JSON_STRICT },
|
||||
{ "preferredLanguage", SD_JSON_VARIANT_STRING, json_dispatch_locale, offsetof(UserRecord, preferred_language), 0 },
|
||||
@@ -1287,7 +1243,7 @@ static int dispatch_per_machine(const char *name, sd_json_variant *variant, sd_j
|
||||
{ "diskSize", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
|
||||
{ "diskSizeRelative", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
|
||||
{ "skeletonDirectory", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), SD_JSON_STRICT },
|
||||
{ "accessMode", SD_JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "accessMode", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "tasksMax", SD_JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
|
||||
{ "memoryHigh", SD_JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
|
||||
{ "memoryMax", SD_JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
|
||||
@@ -1397,7 +1353,7 @@ static int dispatch_status(const char *name, sd_json_variant *variant, sd_json_d
|
||||
{ "rateLimitBeginUSec", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, ratelimit_begin_usec), 0 },
|
||||
{ "rateLimitCount", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, ratelimit_count), 0 },
|
||||
{ "removable", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(UserRecord, removable), 0 },
|
||||
{ "accessMode", SD_JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "accessMode", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "fileSystemType", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(UserRecord, file_system_type), SD_JSON_STRICT },
|
||||
{ "fallbackShell", SD_JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, fallback_shell), 0 },
|
||||
{ "fallbackHomeDirectory", SD_JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, fallback_home_directory), 0 },
|
||||
@@ -1633,7 +1589,7 @@ int user_record_load(UserRecord *h, sd_json_variant *v, UserRecordLoadFlags load
|
||||
{ "lastChangeUSec", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, last_change_usec), 0 },
|
||||
{ "lastPasswordChangeUSec", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, last_password_change_usec), 0 },
|
||||
{ "shell", SD_JSON_VARIANT_STRING, json_dispatch_filename_or_path, offsetof(UserRecord, shell), 0 },
|
||||
{ "umask", SD_JSON_VARIANT_UNSIGNED, json_dispatch_umask, offsetof(UserRecord, umask), 0 },
|
||||
{ "umask", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, offsetof(UserRecord, umask), SD_JSON_STRICT },
|
||||
{ "environment", SD_JSON_VARIANT_ARRAY, json_dispatch_strv_environment, offsetof(UserRecord, environment), 0 },
|
||||
{ "timeZone", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(UserRecord, time_zone), SD_JSON_STRICT },
|
||||
{ "preferredLanguage", SD_JSON_VARIANT_STRING, json_dispatch_locale, offsetof(UserRecord, preferred_language), 0 },
|
||||
@@ -1647,7 +1603,7 @@ int user_record_load(UserRecord *h, sd_json_variant *v, UserRecordLoadFlags load
|
||||
{ "diskSize", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 },
|
||||
{ "diskSizeRelative", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 },
|
||||
{ "skeletonDirectory", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), SD_JSON_STRICT },
|
||||
{ "accessMode", SD_JSON_VARIANT_UNSIGNED, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "accessMode", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, offsetof(UserRecord, access_mode), 0 },
|
||||
{ "tasksMax", SD_JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, tasks_max), 0 },
|
||||
{ "memoryHigh", SD_JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_high), 0 },
|
||||
{ "memoryMax", SD_JSON_VARIANT_UNSIGNED, json_dispatch_tasks_or_memory_max, offsetof(UserRecord, memory_max), 0 },
|
||||
|
||||
@@ -113,6 +113,8 @@ static SD_VARLINK_DEFINE_METHOD(
|
||||
SD_VARLINK_DEFINE_INPUT(parentFileDescriptor, SD_VARLINK_INT, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("Name of the directory to create."),
|
||||
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("Access mode of the directory to create. Note that the suid, sgid, sticky, world-writable bit is unconditionally masked off."),
|
||||
SD_VARLINK_DEFINE_INPUT(mode, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_POLKIT_INPUT,
|
||||
SD_VARLINK_FIELD_COMMENT("File descriptor referencing the newly created directory."),
|
||||
SD_VARLINK_DEFINE_OUTPUT(directoryFileDescriptor, SD_VARLINK_INT, 0));
|
||||
|
||||
@@ -1477,4 +1477,50 @@ TEST(unit_name) {
|
||||
&data), EINVAL);
|
||||
}
|
||||
|
||||
TEST(access_mode) {
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
ASSERT_OK(sd_json_parse("{"
|
||||
" \"a\" : \"0755\", "
|
||||
" \"b\" : 448, "
|
||||
" \"c\" : null, "
|
||||
" \"d\" : \"01755\" "
|
||||
"}",
|
||||
/* flags= */ 0,
|
||||
&v,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL));
|
||||
|
||||
struct {
|
||||
mode_t a, b, c, d;
|
||||
} mm = { 1, 2, 3, 4 };
|
||||
|
||||
ASSERT_OK(sd_json_dispatch(
|
||||
v,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "a", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, voffsetof(mm, a), 0 },
|
||||
{ "b", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, voffsetof(mm, b), 0 },
|
||||
{ "c", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, voffsetof(mm, c), 0 },
|
||||
{ "d", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, voffsetof(mm, d), 0 },
|
||||
{},
|
||||
},
|
||||
/* flags= */ 0,
|
||||
&mm));
|
||||
|
||||
ASSERT_EQ(mm.a, (mode_t) 0755);
|
||||
ASSERT_EQ(mm.b, (mode_t) 0700);
|
||||
ASSERT_EQ(mm.c, MODE_INVALID);
|
||||
ASSERT_EQ(mm.d, (mode_t) 01755);
|
||||
|
||||
/* retry with SD_JSON_STRICT, where 'd' should not parse anymore */
|
||||
ASSERT_ERROR(sd_json_dispatch(
|
||||
v,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "d", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode, voffsetof(mm, d), SD_JSON_STRICT },
|
||||
{},
|
||||
},
|
||||
/* flags= */ SD_JSON_ALLOW_EXTENSIONS,
|
||||
&mm), ERANGE);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
Reference in New Issue
Block a user