From: Lennart Poettering Date: Thu, 28 Aug 2025 09:19:41 +0000 (+0200) Subject: repart: add basic Varlink support, for now only with a ListCandidateDevices() call X-Git-Tag: v259-rc1~467^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=19f2baccced128ea9a3f823e6007aab946b39e39;p=thirdparty%2Fsystemd.git repart: add basic Varlink support, for now only with a ListCandidateDevices() call --- diff --git a/src/repart/repart.c b/src/repart/repart.c index 74c348d030e..0c7b77f8450 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -9,6 +9,7 @@ #include "sd-id128.h" #include "sd-json.h" +#include "sd-varlink.h" #include "alloc-util.h" #include "ask-password-api.h" @@ -79,6 +80,8 @@ #include "tpm2-pcr.h" #include "tpm2-util.h" #include "utf8.h" +#include "varlink-io.systemd.Repart.h" +#include "varlink-util.h" #include "xattr-util.h" /* If not configured otherwise use a minimal partition size of 10M */ @@ -202,6 +205,7 @@ static char *arg_generate_fstab = NULL; static char *arg_generate_crypttab = NULL; static Set *arg_verity_settings = NULL; static bool arg_relax_copy_block_security = false; +static bool arg_varlink = false; STATIC_DESTRUCTOR_REGISTER(arg_node, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); @@ -9347,6 +9351,14 @@ static int parse_argv( if (arg_append_fstab && !arg_generate_fstab) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No --generate-fstab= specified for --append-fstab=%s.", append_mode_to_string(arg_append_fstab)); + r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT); + if (r < 0) + return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m"); + if (r > 0) { + arg_varlink = true; + arg_pager_flags |= PAGER_DISABLE; + } + *ret_certificate = TAKE_PTR(certificate); *ret_private_key = TAKE_PTR(private_key); *ret_ui = TAKE_PTR(ui); @@ -9771,6 +9783,88 @@ static int determine_auto_size(Context *c) { return 0; } +static int vl_method_list_candidate_devices( + sd_varlink *link, + sd_json_variant *parameters, + sd_varlink_method_flags_t flags, + void *userdata) { + + int r; + + assert(link); + + r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL); + if (r != 0) + return r; + + if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE)) + return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL); + + BlockDevice *l = NULL; + size_t n = 0; + CLEANUP_ARRAY(l, n, block_device_array_free); + + r = blockdev_list(BLOCKDEV_LIST_SHOW_SYMLINKS|BLOCKDEV_LIST_REQUIRE_PARTITION_SCANNING|BLOCKDEV_LIST_IGNORE_ZRAM, &l, &n); + if (r < 0) + return r; + + if (n == 0) + return sd_varlink_error(link, "io.systemd.Repart.NoCandidateDevices", NULL); + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + FOREACH_ARRAY(d, l, n) { + if (v) { + r = sd_varlink_notify(link, v); + if (r < 0) + return r; + + v = sd_json_variant_unref(v); + } + + r = sd_json_buildo( + &v, + SD_JSON_BUILD_PAIR_STRING("node", d->node), + JSON_BUILD_PAIR_STRV_NON_EMPTY("symlinks", d->symlinks), + SD_JSON_BUILD_PAIR_CONDITION(d->diskseq != UINT64_MAX, "diskseq", SD_JSON_BUILD_INTEGER(d->diskseq)), + SD_JSON_BUILD_PAIR_CONDITION(d->size != UINT64_MAX, "sizeBytes", SD_JSON_BUILD_INTEGER(d->size))); + if (r < 0) + return r; + } + + assert(v); + return sd_varlink_reply(link, v); +} + +static int vl_server(void) { + _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL; + int r; + + /* Invocation as Varlink service */ + + r = varlink_server_new( + &varlink_server, + SD_VARLINK_SERVER_ROOT_ONLY, + /* userdata= */ NULL); + if (r < 0) + return log_error_errno(r, "Failed to allocate Varlink server: %m"); + + r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_Repart); + if (r < 0) + return log_error_errno(r, "Failed to add Varlink interface: %m"); + + r = sd_varlink_server_bind_method_many( + varlink_server, + "io.systemd.Repart.ListCandidateDevices", vl_method_list_candidate_devices); + if (r < 0) + return log_error_errno(r, "Failed to bind Varlink methods: %m"); + + r = sd_varlink_server_loop_auto(varlink_server); + if (r < 0) + return log_error_errno(r, "Failed to run Varlink event loop: %m"); + + return 0; +} + static int run(int argc, char *argv[]) { _cleanup_(X509_freep) X509 *certificate = NULL; _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL; @@ -9787,6 +9881,13 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; +#if HAVE_LIBCRYPTSETUP + cryptsetup_enable_logging(NULL); +#endif + + if (arg_varlink) + return vl_server(); + r = parse_proc_cmdline_factory_reset(); if (r < 0) return r; @@ -9795,10 +9896,6 @@ static int run(int argc, char *argv[]) { if (r < 0) return r; -#if HAVE_LIBCRYPTSETUP - cryptsetup_enable_logging(NULL); -#endif - if (arg_image) { assert(!arg_root); diff --git a/src/shared/meson.build b/src/shared/meson.build index 790b1f2825c..4b84dd9cea3 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -204,6 +204,7 @@ shared_sources = files( 'varlink-io.systemd.Network.c', 'varlink-io.systemd.PCRExtend.c', 'varlink-io.systemd.PCRLock.c', + 'varlink-io.systemd.Repart.c', 'varlink-io.systemd.Resolve.c', 'varlink-io.systemd.Resolve.Monitor.c', 'varlink-io.systemd.Udev.c', diff --git a/src/shared/varlink-io.systemd.Repart.c b/src/shared/varlink-io.systemd.Repart.c new file mode 100644 index 00000000000..4f531fe39c8 --- /dev/null +++ b/src/shared/varlink-io.systemd.Repart.c @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-varlink-idl.h" + +#include "varlink-io.systemd.Repart.h" + +static SD_VARLINK_DEFINE_METHOD( + ListCandidateDevices, + SD_VARLINK_FIELD_COMMENT("The device node path of the block device."), + SD_VARLINK_DEFINE_OUTPUT(node, SD_VARLINK_STRING, 0), + SD_VARLINK_FIELD_COMMENT("List of symlinks pointing to the device node, if any."), + SD_VARLINK_DEFINE_OUTPUT(symlinks, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("The Linux kernel disk sequence number identifying the medium."), + SD_VARLINK_DEFINE_OUTPUT(diskseq, SD_VARLINK_INT, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("The size of the block device in bytes."), + SD_VARLINK_DEFINE_OUTPUT(sizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); + +static SD_VARLINK_DEFINE_ERROR(NoCandidateDevices); + +SD_VARLINK_DEFINE_INTERFACE( + io_systemd_Repart, + "io.systemd.Repart", + SD_VARLINK_INTERFACE_COMMENT("API for declaratively re-partitioning disks using systemd-repart."), + SD_VARLINK_SYMBOL_COMMENT("Return a list of candidate block devices, i.e. that support partition scanning and other requirements for successful operation."), + &vl_method_ListCandidateDevices, + SD_VARLINK_SYMBOL_COMMENT("Not a single candidate block device could be found."), + &vl_error_NoCandidateDevices); diff --git a/src/shared/varlink-io.systemd.Repart.h b/src/shared/varlink-io.systemd.Repart.h new file mode 100644 index 00000000000..7c7cb7dd79f --- /dev/null +++ b/src/shared/varlink-io.systemd.Repart.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "sd-varlink-idl.h" + +extern const sd_varlink_interface vl_interface_io_systemd_Repart; diff --git a/units/meson.build b/units/meson.build index 4f47a3b2bde..c5b99e4e04c 100644 --- a/units/meson.build +++ b/units/meson.build @@ -651,6 +651,15 @@ units = [ 'conditions' : ['ENABLE_REPART'], 'symlinks' : ['sysinit.target.wants/', 'initrd-root-fs.target.wants/'], }, + { + 'file' : 'systemd-repart.socket', + 'conditions' : ['ENABLE_REPART'], + 'symlinks' : ['sockets.target.wants/'], + }, + { + 'file' : 'systemd-repart@.service', + 'conditions' : ['ENABLE_REPART'], + }, { 'file' : 'systemd-resolved.service.in', 'conditions' : ['ENABLE_RESOLVE'], diff --git a/units/systemd-repart.socket b/units/systemd-repart.socket new file mode 100644 index 00000000000..0c77165e1c5 --- /dev/null +++ b/units/systemd-repart.socket @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Disk Repartitioning Service Socket +Documentation=man:systemd-repart(8) +DefaultDependencies=no +Before=sockets.target +Conflicts=shutdown.target +Before=shutdown.target + +[Socket] +ListenStream=/run/systemd/io.systemd.Repart +FileDescriptorName=varlink +SocketMode=0600 +Accept=yes diff --git a/units/systemd-repart@.service b/units/systemd-repart@.service new file mode 100644 index 00000000000..f8061edd0a9 --- /dev/null +++ b/units/systemd-repart@.service @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Disk Repartitioning Service +Documentation=man:systemd-repart.service(8) +DefaultDependencies=no +Wants=modprobe@loop.service modprobe@dm_mod.service +After=modprobe@loop.service modprobe@dm_mod.service systemd-tpm2-setup-early.service +Conflicts=shutdown.target +Before=shutdown.target + +[Service] +ExecStart=systemd-repart