summaryrefslogtreecommitdiffstats
path: root/src/storagetm
diff options
context:
space:
mode:
Diffstat (limited to 'src/storagetm')
-rw-r--r--src/storagetm/storagetm.c152
1 files changed, 148 insertions, 4 deletions
diff --git a/src/storagetm/storagetm.c b/src/storagetm/storagetm.c
index 8d36184b76..c9f6dd9214 100644
--- a/src/storagetm/storagetm.c
+++ b/src/storagetm/storagetm.c
@@ -13,9 +13,11 @@
#include "fileio.h"
#include "format-util.h"
#include "fs-util.h"
+#include "id128-util.h"
#include "local-addresses.h"
#include "loop-util.h"
#include "main-func.h"
+#include "os-util.h"
#include "parse-argument.h"
#include "path-util.h"
#include "plymouth-util.h"
@@ -220,7 +222,137 @@ static NvmeSubsystem *nvme_subsystem_destroy(NvmeSubsystem *s) {
DEFINE_TRIVIAL_CLEANUP_FUNC(NvmeSubsystem*, nvme_subsystem_destroy);
-static int nvme_subsystem_add(const char *node, int consumed_fd, NvmeSubsystem **ret) {
+static int nvme_subsystem_write_metadata(int subsystem_fd, sd_device *device) {
+ _cleanup_free_ char *image_id = NULL, *image_version = NULL, *os_id = NULL, *os_version = NULL, *combined_model = NULL, *synthetic_serial = NULL;
+ const char *hwmodel = NULL, *hwserial = NULL, *w;
+ int r;
+
+ assert(subsystem_fd >= 0);
+
+ (void) parse_os_release(
+ /* root= */ NULL,
+ "IMAGE_ID", &image_id,
+ "IMAGE_VERSION", &image_version,
+ "ID", &os_id,
+ "VERSION_ID", &os_version);
+
+ if (device) {
+ (void) device_get_model_string(device, &hwmodel);
+ (void) sd_device_get_property_value(device, "ID_SERIAL_SHORT", &hwserial);
+ }
+
+ w = secure_getenv("SYSTEMD_NVME_MODEL");
+ if (!w) {
+ if (hwmodel && (image_id || os_id)) {
+ if (asprintf(&combined_model, "%s (%s)", hwmodel, image_id ?: os_id) < 0)
+ return log_oom();
+ w = combined_model;
+ } else
+ w = hwmodel ?: image_id ?: os_id;
+ }
+ if (w) {
+ _cleanup_free_ char *truncated = strndup(w, 40); /* kernel refuses more than 40 chars (as per nvme spec) */
+
+ /* The default string stored in 'attr_model' is "Linux" btw. */
+ r = write_string_file_at(subsystem_fd, "attr_model", truncated, WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set model of subsystem to '%s', ignoring: %m", w);
+ }
+
+ w = secure_getenv("SYSTEMD_NVME_FIRMWARE");
+ if (!w)
+ w = image_version ?: os_version;
+ if (w) {
+ _cleanup_free_ char *truncated = strndup(w, 8); /* kernel refuses more than 8 chars (as per nvme spec) */
+ if (!truncated)
+ return log_oom();
+
+ /* The default string stored in 'attr_firmware' is `uname -r` btw, but truncated to 8 chars. */
+ r = write_string_file_at(subsystem_fd, "attr_firmware", truncated, WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set model of subsystem to '%s', ignoring: %m", truncated);
+ }
+
+ w = secure_getenv("SYSTEMD_NVME_SERIAL");
+ if (!w) {
+ if (hwserial)
+ w = hwserial;
+ else {
+ sd_id128_t mid;
+
+ r = sd_id128_get_machine_app_specific(SD_ID128_MAKE(39,7f,4d,bf,1e,bf,46,6d,b3,cb,45,b8,0d,49,5b,c1), &mid);
+ if (r < 0)
+ log_warning_errno(r, "Failed to get machine ID, ignoring: %m");
+ else {
+ if (asprintf(&synthetic_serial, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(mid)) < 0)
+ return log_oom();
+ w = synthetic_serial;
+ }
+ }
+ }
+ if (w) {
+ _cleanup_free_ char *truncated = strndup(w, 20); /* kernel refuses more than 20 chars (as per nvme spec) */
+ if (!truncated)
+ return log_oom();
+
+ r = write_string_file_at(subsystem_fd, "attr_serial", truncated, WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set serial of subsystem to '%s', ignoring: %m", truncated);
+ }
+
+ return 0;
+}
+
+static int nvme_namespace_write_metadata(int namespace_fd, sd_device *device, const char *node) {
+ sd_id128_t id = SD_ID128_NULL;
+ const char *e;
+ int r;
+
+ assert(namespace_fd >= 0);
+
+ e = secure_getenv("SYSTEMD_NVME_UUID");
+ if (e) {
+ r = sd_id128_from_string(e, &id);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse $SYSTEMD_NVME_UUID, ignoring: %s", e);
+ }
+
+ if (sd_id128_is_null(id)) {
+ const char *serial = NULL;
+ sd_id128_t mid = SD_ID128_NULL;
+
+ /* We combine machine ID and ID_SERIAL and hash a UUID from it */
+
+ if (device) {
+ (void) sd_device_get_property_value(device, "ID_SERIAL", &serial);
+ if (!serial)
+ sd_device_get_devpath(device, &serial);
+ } else
+ serial = node;
+
+ r = sd_id128_get_machine(&mid);
+ if (r < 0)
+ log_warning_errno(r, "Failed to get machine ID, ignoring: %m");
+
+ size_t l = sizeof(mid) + strlen_ptr(serial);
+ _cleanup_free_ void *j = malloc(l + 1);
+ if (!j)
+ return log_oom();
+
+ strcpy(mempcpy(j, &mid, sizeof(mid)), strempty(serial));
+
+ id = id128_digest(j, l);
+ }
+
+ r = write_string_file_at(namespace_fd, "device_uuid", SD_ID128_TO_UUID_STRING(id), WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set uuid of namespace to '%s', ignoring: %m", SD_ID128_TO_UUID_STRING(id));
+
+ return 0;
+}
+
+static int nvme_subsystem_add(const char *node, int consumed_fd, sd_device *device, NvmeSubsystem **ret) {
+ _cleanup_(sd_device_unrefp) sd_device *allocated_device = NULL;
_cleanup_close_ int fd = consumed_fd; /* always take possession of the fd */
int r;
@@ -246,7 +378,15 @@ static int nvme_subsystem_add(const char *node, int consumed_fd, NvmeSubsystem *
struct stat st;
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to fstat '%s': %m", node);
- if (!S_ISBLK(st.st_mode)) {
+ if (S_ISBLK(st.st_mode)) {
+ if (!device) {
+ r = sd_device_new_from_devnum(&allocated_device, 'b', st.st_dev);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get device information for device '%s': %m", node);
+
+ device = allocated_device;
+ }
+ } else {
r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Not a block device or regular file, refusing: %s", node);
@@ -271,11 +411,15 @@ static int nvme_subsystem_add(const char *node, int consumed_fd, NvmeSubsystem *
if (r < 0)
return log_error_errno(r, "Failed to set 'attr_allow_any_host' flag: %m");
+ (void) nvme_subsystem_write_metadata(subsystem_fd, device);
+
_cleanup_close_ int namespace_fd = -EBADF;
namespace_fd = open_mkdir_at(subsystem_fd, "namespaces/1", O_EXCL|O_RDONLY|O_CLOEXEC, 0777);
if (namespace_fd < 0)
return log_error_errno(namespace_fd, "Failed to create NVME namespace '1': %m");
+ (void) nvme_namespace_write_metadata(namespace_fd, device, node);
+
/* We use /proc/$PID/fd/$FD rather than /proc/self/fd/$FD, because this string is visible to others
* via configfs, and by including the PID it's clear to who the stuff belongs. */
r = write_string_file_at(namespace_fd, "device_path", FORMAT_PROC_PID_FD_PATH(0, fd), WRITE_STRING_FILE_DISABLE_BUFFER);
@@ -826,7 +970,7 @@ static int device_added(Context *c, sd_device *device) {
}
_cleanup_(nvme_subsystem_destroyp) NvmeSubsystem *s = NULL;
- r = nvme_subsystem_add(devname, TAKE_FD(fd), &s);
+ r = nvme_subsystem_add(devname, TAKE_FD(fd), device, &s);
if (r < 0)
return r;
@@ -974,7 +1118,7 @@ static int run(int argc, char* argv[]) {
STRV_FOREACH(i, arg_devices) {
_cleanup_(nvme_subsystem_destroyp) NvmeSubsystem *subsys = NULL;
- r = nvme_subsystem_add(*i, -EBADF, &subsys);
+ r = nvme_subsystem_add(*i, -EBADF, /* device= */ NULL, &subsys);
if (r < 0)
return r;