#include "path-util.h"
#include "proc-cmdline.h"
#include "recurse-dir.h"
+#include "smbios11.h"
#include "strv.h"
#include "virt.h"
return 0;
for (unsigned i = 0;; i++) {
- struct dmi_field_header {
- uint8_t type;
- uint8_t length;
- uint16_t handle;
- uint8_t count;
- char contents[];
- } _packed_ *dmi_field_header;
- _cleanup_free_ char *p = NULL;
- _cleanup_free_ void *data = NULL;
+ _cleanup_free_ char *data = NULL;
size_t size;
- assert_cc(offsetof(struct dmi_field_header, contents) == 5);
-
- if (asprintf(&p, "/sys/firmware/dmi/entries/11-%u/raw", i) < 0)
- return log_oom();
-
- r = read_virtual_file(p, sizeof(dmi_field_header) + CREDENTIALS_TOTAL_SIZE_MAX, (char**) &data, &size);
+ r = read_smbios11_field(i, CREDENTIALS_TOTAL_SIZE_MAX, &data, &size);
if (r < 0) {
/* Once we reach ENOENT there are no more DMI Type 11 fields around. */
- log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to open '%s', ignoring: %m", p);
+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read SMBIOS type #11 object %u, ignoring: %m", i);
break;
}
- if (size < offsetof(struct dmi_field_header, contents))
- return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "DMI field header of '%s' too short.", p);
-
- dmi_field_header = data;
- if (dmi_field_header->type != 11 ||
- dmi_field_header->length != offsetof(struct dmi_field_header, contents))
- return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Invalid DMI field header.");
-
- r = parse_smbios_strings(c, dmi_field_header->contents, size - offsetof(struct dmi_field_header, contents));
+ r = parse_smbios_strings(c, data, size);
if (r < 0)
return r;
'service-util.c',
'sleep-config.c',
'smack-util.c',
+ 'smbios11.c',
'socket-label.c',
'socket-netlink.c',
'spawn-ask-password-agent.c',
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "fileio.h"
+#include "macro.h"
+#include "smbios11.h"
+#include "virt.h"
+
+int read_smbios11_field(unsigned i, size_t max_size, char **ret_data, size_t *ret_size) {
+ _cleanup_free_ char *p = NULL, *contents = NULL;
+ _cleanup_free_ void *data = NULL;
+ size_t size, contents_size;
+ int r;
+
+ assert(ret_data);
+ assert(ret_size);
+
+ /* Parses DMI OEM strings fields (SMBIOS type 11), as settable with qemu's -smbios type=11,value=… switch. */
+
+ if (detect_container() > 0) /* don't access /sys/ in a container */
+ return -ENOENT;
+
+ if (asprintf(&p, "/sys/firmware/dmi/entries/11-%u/raw", i) < 0)
+ return -ENOMEM;
+
+ struct dmi_field_header {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+ uint8_t count;
+ char contents[];
+ } _packed_ *dmi_field_header;
+
+ assert_cc(offsetof(struct dmi_field_header, contents) == 5);
+
+ r = read_virtual_file(
+ p,
+ max_size >= SIZE_MAX - offsetof(struct dmi_field_header, contents) ? SIZE_MAX :
+ sizeof(dmi_field_header) + max_size,
+ (char**) &data, &size);
+ if (r < 0)
+ return r;
+
+ if (size < offsetof(struct dmi_field_header, contents))
+ return -EBADMSG;
+
+ dmi_field_header = data;
+ if (dmi_field_header->type != 11 ||
+ dmi_field_header->length != offsetof(struct dmi_field_header, contents))
+ return -EBADMSG;
+
+ contents_size = size - offsetof(struct dmi_field_header, contents);
+ contents = memdup_suffix0(dmi_field_header->contents, contents_size);
+ if (!contents)
+ return -ENOMEM;
+
+ *ret_data = TAKE_PTR(contents);
+ *ret_size = contents_size;
+
+ return r; /* NB! read_virtual_file() returns 0 on incomplete reads, and 1 in complete reads */
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <sys/types.h>
+
+int read_smbios11_field(unsigned i, size_t max_size, char **ret_data, size_t *ret_size);