shared: add storage_acquire_volume() helper
storagectl's mount.storage helper bundles "open StorageProvider socket + Acquire() + dispatch reply + take fd" inline. Future consumers (systemd-vmspawn boot-time --bind-volume, machinectl bind-volume) need the same dance. Factor it into a single libshared helper that takes the Acquire() parameters by value and returns the fd plus the actual type/read-only flags. Library code, so no logging — varlink errors are surfaced via sd_varlink_error_to_errno() and the StorageProvider error_id is returned to the caller via reterr_error_id (caller decides how to format messages). Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
@@ -268,6 +268,8 @@ enum {
|
||||
SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_UNSIGNED(value))
|
||||
#define JSON_BUILD_PAIR_CONDITION_BOOLEAN(condition, name, value) \
|
||||
SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_BOOLEAN(value))
|
||||
#define JSON_BUILD_PAIR_CONDITION_STRING(condition, name, value) \
|
||||
SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_STRING(value))
|
||||
#define JSON_BUILD_PAIR_CONDITION_STRV(condition, name, value) \
|
||||
SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_STRV(value))
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "json-util.h"
|
||||
#include "machine-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "string-table.h"
|
||||
#include "storage-util.h"
|
||||
|
||||
@@ -21,3 +29,102 @@ DEFINE_STRING_TABLE_LOOKUP(create_mode, CreateMode);
|
||||
|
||||
JSON_DISPATCH_ENUM_DEFINE(json_dispatch_volume_type, VolumeType, volume_type_from_string);
|
||||
JSON_DISPATCH_ENUM_DEFINE(json_dispatch_create_mode, CreateMode, create_mode_from_string);
|
||||
|
||||
void storage_acquire_reply_done(StorageAcquireReply *reply) {
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
reply->fd = safe_close(reply->fd);
|
||||
}
|
||||
|
||||
int storage_acquire_volume(
|
||||
RuntimeScope scope,
|
||||
const BindVolume *bv,
|
||||
bool allow_interactive_auth,
|
||||
char **reterr_error_id,
|
||||
StorageAcquireReply *ret) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(bv);
|
||||
assert(bv->provider);
|
||||
assert(bv->volume);
|
||||
assert(ret);
|
||||
|
||||
/* Defense-in-depth: this is a libshared helper that may grow new callers; reject
|
||||
* provider names that could escape the StorageProvider runtime directory. */
|
||||
if (!storage_provider_name_is_valid(bv->provider))
|
||||
return -EINVAL;
|
||||
|
||||
_cleanup_free_ char *socket_path = NULL;
|
||||
r = runtime_directory_generic(scope, "systemd/io.systemd.StorageProvider", &socket_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!path_extend(&socket_path, bv->provider))
|
||||
return -ENOMEM;
|
||||
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *link = NULL;
|
||||
r = sd_varlink_connect_address(&link, socket_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_varlink_set_allow_fd_passing_input(link, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sd_json_variant *mreply = NULL;
|
||||
const char *merror_id = NULL;
|
||||
r = sd_varlink_callbo(
|
||||
link,
|
||||
"io.systemd.StorageProvider.Acquire",
|
||||
&mreply,
|
||||
&merror_id,
|
||||
SD_JSON_BUILD_PAIR_STRING("name", bv->volume),
|
||||
JSON_BUILD_PAIR_CONDITION_STRING(bv->create_mode >= 0, "createMode", create_mode_to_string(bv->create_mode)),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("template", bv->template),
|
||||
JSON_BUILD_PAIR_TRISTATE_NON_NULL("readOnly", read_only_mode_to_tristate(bv->read_only)),
|
||||
JSON_BUILD_PAIR_CONDITION_STRING(bv->request_as >= 0, "requestAs", volume_type_to_string(bv->request_as)),
|
||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("createSizeBytes", bv->create_size_bytes, UINT64_MAX),
|
||||
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", allow_interactive_auth));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (merror_id) {
|
||||
if (reterr_error_id) {
|
||||
char *copy = strdup(merror_id);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
*reterr_error_id = copy;
|
||||
}
|
||||
|
||||
r = sd_varlink_error_to_errno(merror_id, mreply);
|
||||
return r == -EBADR ? -EPROTO : r;
|
||||
}
|
||||
|
||||
/* tmp.fd holds the JSON fd index until sd_varlink_take_fd() swaps it for the real fd. */
|
||||
StorageAcquireReply tmp = STORAGE_ACQUIRE_REPLY_INIT;
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "fileDescriptorIndex", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, voffsetof(StorageAcquireReply, fd), SD_JSON_MANDATORY },
|
||||
{ "readOnly", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, voffsetof(StorageAcquireReply, read_only), 0 },
|
||||
{ "type", SD_JSON_VARIANT_STRING, json_dispatch_volume_type, voffsetof(StorageAcquireReply, type), SD_JSON_MANDATORY },
|
||||
{ "baseUID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, voffsetof(StorageAcquireReply, base_uid), 0 },
|
||||
{ "baseGID", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, voffsetof(StorageAcquireReply, base_gid), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(mreply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (tmp.fd < 0)
|
||||
return -EBADMSG;
|
||||
|
||||
_cleanup_close_ int fd = sd_varlink_take_fd(link, tmp.fd);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
tmp.fd = TAKE_FD(fd);
|
||||
*ret = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,3 +41,32 @@ static inline bool storage_template_name_is_valid(const char *n) {
|
||||
static inline bool storage_provider_name_is_valid(const char *n) {
|
||||
return string_is_safe(n, STRING_FILENAME);
|
||||
}
|
||||
|
||||
typedef struct StorageAcquireReply {
|
||||
int fd;
|
||||
VolumeType type;
|
||||
int read_only;
|
||||
uid_t base_uid;
|
||||
gid_t base_gid;
|
||||
} StorageAcquireReply;
|
||||
|
||||
#define STORAGE_ACQUIRE_REPLY_INIT \
|
||||
(StorageAcquireReply) { \
|
||||
.fd = -EBADF, \
|
||||
.type = _VOLUME_TYPE_INVALID, \
|
||||
.read_only = -1, \
|
||||
.base_uid = UID_INVALID, \
|
||||
.base_gid = GID_INVALID, \
|
||||
}
|
||||
|
||||
void storage_acquire_reply_done(StorageAcquireReply *reply);
|
||||
|
||||
/* On varlink failure, reterr_error_id (if non-NULL) is set to the io.systemd.StorageProvider.*
|
||||
* error name. The reply is untouched on any error. */
|
||||
typedef struct BindVolume BindVolume;
|
||||
int storage_acquire_volume(
|
||||
RuntimeScope scope,
|
||||
const BindVolume *bv,
|
||||
bool allow_interactive_auth,
|
||||
char **reterr_error_id,
|
||||
StorageAcquireReply *ret);
|
||||
|
||||
Reference in New Issue
Block a user