summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2024-11-15 11:38:30 +0100
committerLennart Poettering <lennart@poettering.net>2024-12-18 17:38:42 +0100
commit8f114904fc0ee5b3d4b12cfb0231d90d5142f9c0 (patch)
treeb39f20f86e85a131ceccee59ea68b09eb18155c6
parentman: Document generator sandbox environment (diff)
downloadsystemd-8f114904fc0ee5b3d4b12cfb0231d90d5142f9c0.tar.xz
systemd-8f114904fc0ee5b3d4b12cfb0231d90d5142f9c0.zip
analyze: add verb for showing system's CHIDs
We have the code already, expose it in systemd-analyze too. This should make it easier to debug the CHID use in the UKIs with onboard tooling.
-rw-r--r--man/systemd-analyze.xml36
-rw-r--r--shell-completion/bash/systemd-analyze2
-rw-r--r--src/analyze/analyze-chid.c224
-rw-r--r--src/analyze/analyze-chid.h4
-rw-r--r--src/analyze/analyze.c3
-rw-r--r--src/analyze/meson.build1
-rw-r--r--src/fundamental/chid-fundamental.c2
-rw-r--r--src/fundamental/chid-fundamental.h2
-rwxr-xr-xtest/units/TEST-65-ANALYZE.sh5
9 files changed, 277 insertions, 2 deletions
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 68d006a1ce..cf005db70b 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -205,6 +205,11 @@
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">smbios11</arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>systemd-analyze</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain">chid</arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -1084,6 +1089,37 @@ io.systemd.credential:vmm.notify_socket=vsock-stream:2:254570042
<xi:include href="version-info.xml" xpointer="v257"/>
</refsect2>
+ <refsect2>
+ <title><command>systemd-analyze chid</command></title>
+
+ <para>Shows a list of Computer Hardware IDs (CHIDs) of the local system. These IDs identify the
+ system's computer hardware, based on SMBIOS data. See <ulink
+ url="https://learn.microsoft.com/en-us/windows-hardware/drivers/dashboard/using-chids">Using Computer
+ Hardware IDs (CHIDs)</ulink> for details about CHIDs.</para>
+
+ <example>
+ <title>Example output</title>
+ <programlisting>$ systemd-analyze chid
+TYPE INPUT CHID
+ 3 MFPSmp 520537c0-3b59-504f-b062-9682ea236b21
+ 4 MFPS-- edf05dc8-a53d-5b2c-8023-630bca2a2463
+ 5 MFP--- ebc6a4d9-ec48-537a-916b-c69fa4fdd814
+ 6 M--Smp 5ebe4bba-f598-5e90-9ff2-9fd0d3211465
+ 7 M--S-- 1a3fb835-b42a-5f9c-a38c-eff5bfd5c41d
+ 8 M-P-mp 2a831dce-8163-5bad-8406-435b8c752dd8
+ 9 M-P--- 7c21c878-4a75-50f7-9816-21e811588da0
+ 10 MF--mp 9a003537-bcc5-500e-b10a-8d8892e4fc64
+ 11 MF---- bb9122bb-8a5c-50d2-a742-a85beb719909
+ 13 M---mp bfc36935-5032-5987-a0a3-6311f01de33a
+
+LEGEND: M → sys_vendor (LENOVO) ┄ F → product_family (ThinkPad X1 Carbon Gen 9) ┄ P → product_name (20XW0055GE)
+ S → product_sku (LENOVO_MT_20XW_BU_Think_FM_ThinkPad X1 Carbon Gen 9) ┄ m → board_vendor (LENOVO)
+ p → board_name (20XW0055GE)</programlisting>
+ </example>
+
+ <xi:include href="version-info.xml" xpointer="v258"/>
+ </refsect2>
+
</refsect1>
<refsect1>
diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze
index caec77e718..41a2151e12 100644
--- a/shell-completion/bash/systemd-analyze
+++ b/shell-completion/bash/systemd-analyze
@@ -67,7 +67,7 @@ _systemd_analyze() {
)
local -A VERBS=(
- [STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2 smbios11'
+ [STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2 smbios11 chid'
[CRITICAL_CHAIN]='critical-chain'
[DOT]='dot'
[DUMP]='dump'
diff --git a/src/analyze/analyze-chid.c b/src/analyze/analyze-chid.c
new file mode 100644
index 0000000000..5bb50f54d8
--- /dev/null
+++ b/src/analyze/analyze-chid.c
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "analyze.h"
+#include "analyze-chid.h"
+#include "chid-fundamental.h"
+#include "efi-api.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "format-table.h"
+#include "parse-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "virt.h"
+
+static int parse_chid_type(const char *s, size_t *ret) {
+ unsigned u;
+ int r;
+
+ assert(s);
+
+ r = safe_atou(s, &u);
+ if (r < 0)
+ return r;
+ if (u >= CHID_TYPES_MAX)
+ return -ERANGE;
+
+ if (ret)
+ *ret = u;
+
+ return 0;
+}
+
+static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
+ [CHID_SMBIOS_MANUFACTURER] = 'M',
+ [CHID_SMBIOS_FAMILY] = 'F',
+ [CHID_SMBIOS_PRODUCT_NAME] = 'P',
+ [CHID_SMBIOS_PRODUCT_SKU] = 'S',
+ [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = 'm',
+ [CHID_SMBIOS_BASEBOARD_PRODUCT] = 'p',
+};
+
+static char *chid_smbios_fields_string(uint32_t combination) {
+ _cleanup_free_ char *s = NULL;
+
+ for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
+ char c;
+
+ c = (combination & (UINT32_C(1) << f)) ? chid_smbios_fields_char[f] : '-';
+
+ if (!strextend(&s, CHAR_TO_STR(c)))
+ return NULL;
+ }
+
+ return TAKE_PTR(s);
+}
+
+static int add_chid(Table *table, const EFI_GUID guids[static CHID_TYPES_MAX], size_t t) {
+ int r;
+
+ assert(table);
+ assert(guids);
+ assert(t < CHID_TYPES_MAX);
+
+ sd_id128_t id = efi_guid_to_id128(guids + t);
+
+ if (sd_id128_is_null(id))
+ return 0;
+
+ _cleanup_free_ char *flags = chid_smbios_fields_string(chid_smbios_table[t]);
+ if (!flags)
+ return log_oom();
+
+ r = table_add_many(table,
+ TABLE_UINT, (unsigned) t,
+ TABLE_STRING, flags,
+ TABLE_UUID, id);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ return 0;
+}
+
+static void smbios_fields_free(char16_t *(*fields)[_CHID_SMBIOS_FIELDS_MAX]) {
+ assert(fields);
+
+ FOREACH_ARRAY(i, *fields, _CHID_SMBIOS_FIELDS_MAX)
+ free(*i);
+}
+
+int verb_chid(int argc, char *argv[], void *userdata) {
+
+ static const char *const smbios_files[_CHID_SMBIOS_FIELDS_MAX] = {
+ [CHID_SMBIOS_MANUFACTURER] = "sys_vendor",
+ [CHID_SMBIOS_FAMILY] = "product_family",
+ [CHID_SMBIOS_PRODUCT_NAME] = "product_name",
+ [CHID_SMBIOS_PRODUCT_SKU] = "product_sku",
+ [CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "board_vendor",
+ [CHID_SMBIOS_BASEBOARD_PRODUCT] = "board_name",
+ };
+
+ _cleanup_(table_unrefp) Table *table = NULL;
+ int r;
+
+ if (detect_container() > 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Container environments do not have SMBIOS.");
+
+ table = table_new("type", "input", "chid");
+ if (!table)
+ return log_oom();
+
+ (void) table_set_align_percent(table, table_get_cell(table, 0, 0), 100);
+ (void) table_set_align_percent(table, table_get_cell(table, 0, 1), 50);
+
+ _cleanup_close_ int smbios_fd = open("/sys/class/dmi/id", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ if (smbios_fd < 0)
+ return log_error_errno(errno, "Failed to open SMBIOS sysfs object: %m");
+
+ _cleanup_(smbios_fields_free) char16_t* smbios_fields[_CHID_SMBIOS_FIELDS_MAX] = {};
+ for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
+ _cleanup_free_ char *buf = NULL;
+ size_t size;
+
+ r = read_virtual_file_at(smbios_fd, smbios_files[f], SIZE_MAX, &buf, &size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read SMBIOS field '%s': %m", smbios_files[f]);
+
+ if (size < 1 || buf[size-1] != '\n')
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected SMBIOS field '%s' to end in newline, but it doesn't, refusing.", smbios_files[f]);
+
+ size--;
+
+ smbios_fields[f] = utf8_to_utf16(buf, size);
+ if (!smbios_fields[f])
+ return log_oom();
+ }
+
+ EFI_GUID chids[CHID_TYPES_MAX] = {};
+ chid_calculate((const char16_t* const*) smbios_fields, chids);
+
+ if (strv_isempty(strv_skip(argv, 1)))
+ for (size_t t = 0; t < CHID_TYPES_MAX; t++) {
+ r = add_chid(table, chids, t);
+ if (r < 0)
+ return r;
+ }
+ else {
+ STRV_FOREACH(as, strv_skip(argv, 1)) {
+ size_t t;
+ r = parse_chid_type(*as, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to pare CHID type: %s", *as);
+
+ r = add_chid(table, chids, t);
+ if (r < 0)
+ return r;
+ }
+
+ (void) table_set_sort(table, (size_t) 0);
+ }
+
+ r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
+ if (r < 0)
+ return log_error_errno(r, "Failed to output table: %m");
+
+ if (!sd_json_format_enabled(arg_json_format_flags)) {
+ _cleanup_free_ char *legend = NULL;
+ bool separator = false;
+ size_t w = 0;
+
+ legend = strjoin(ansi_grey(), "LEGEND: ", ansi_normal());
+ if (!legend)
+ return log_oom();
+
+ for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
+ _cleanup_free_ char *c = utf16_to_utf8(smbios_fields[f], SIZE_MAX);
+ if (!c)
+ return log_oom();
+
+ if (!strextend(&legend,
+ ansi_grey(),
+ separator ? " " : "",
+ separator ? special_glyph(SPECIAL_GLYPH_HORIZONTAL_DOTTED) : "",
+ separator ? " " : "",
+ ansi_normal(),
+ CHAR_TO_STR(chid_smbios_fields_char[f]),
+ ansi_grey(),
+ " ",
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
+ " ",
+ ansi_normal(),
+ smbios_files[f],
+ ansi_grey(),
+ " (",
+ ansi_highlight(),
+ c,
+ ansi_grey(),
+ ")",
+ ansi_normal()))
+ return log_oom();
+
+ w += separator * 3 +
+ 4 +
+ utf8_console_width(smbios_files[f]) +
+ 2 +
+ utf8_console_width(c) +
+ 1;
+
+ if (w > 79) {
+ if (!strextend(&legend, "\n "))
+ return log_oom();
+
+ separator = false;
+ w = 8;
+ } else
+ separator = true;
+
+ }
+
+ putchar('\n');
+ puts(legend);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/analyze/analyze-chid.h b/src/analyze/analyze-chid.h
new file mode 100644
index 0000000000..a3f40c6013
--- /dev/null
+++ b/src/analyze/analyze-chid.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int verb_chid(int argc, char *argv[], void *userdata);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index e21f12c65e..ad3dd446ab 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -18,6 +18,7 @@
#include "analyze-calendar.h"
#include "analyze-capability.h"
#include "analyze-cat-config.h"
+#include "analyze-chid.h"
#include "analyze-compare-versions.h"
#include "analyze-condition.h"
#include "analyze-critical-chain.h"
@@ -219,6 +220,7 @@ static int help(int argc, char *argv[], void *userdata) {
" filesystems [NAME...] List known filesystems\n"
" architectures [NAME...] List known architectures\n"
" smbios11 List strings passed via SMBIOS Type #11\n"
+ " chid List local CHIDs\n"
"\n%3$sExpression Evaluation:%4$s\n"
" condition CONDITION... Evaluate conditions and asserts\n"
" compare-versions VERSION1 [OP] VERSION2\n"
@@ -691,6 +693,7 @@ static int run(int argc, char *argv[]) {
{ "srk", VERB_ANY, 1, 0, verb_srk },
{ "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures },
{ "smbios11", VERB_ANY, 1, 0, verb_smbios11 },
+ { "chid", VERB_ANY, VERB_ANY, 0, verb_chid },
{}
};
diff --git a/src/analyze/meson.build b/src/analyze/meson.build
index c42db1a633..5a7c6c9285 100644
--- a/src/analyze/meson.build
+++ b/src/analyze/meson.build
@@ -6,6 +6,7 @@ systemd_analyze_sources = files(
'analyze-calendar.c',
'analyze-capability.c',
'analyze-cat-config.c',
+ 'analyze-chid.c',
'analyze-compare-versions.c',
'analyze-condition.c',
'analyze-critical-chain.c',
diff --git a/src/fundamental/chid-fundamental.c b/src/fundamental/chid-fundamental.c
index 01045176f5..9c719a334d 100644
--- a/src/fundamental/chid-fundamental.c
+++ b/src/fundamental/chid-fundamental.c
@@ -61,7 +61,7 @@ static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIE
ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80);
}
-static const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
+const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
[3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
diff --git a/src/fundamental/chid-fundamental.h b/src/fundamental/chid-fundamental.h
index 1e582932fd..41f7be337d 100644
--- a/src/fundamental/chid-fundamental.h
+++ b/src/fundamental/chid-fundamental.h
@@ -23,5 +23,7 @@ typedef enum ChidSmbiosFields {
_CHID_SMBIOS_FIELDS_MAX,
} ChidSmbiosFields;
+extern const uint32_t chid_smbios_table[CHID_TYPES_MAX];
+
/* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]);
diff --git a/test/units/TEST-65-ANALYZE.sh b/test/units/TEST-65-ANALYZE.sh
index 2fa368a678..ac39c42da4 100755
--- a/test/units/TEST-65-ANALYZE.sh
+++ b/test/units/TEST-65-ANALYZE.sh
@@ -990,6 +990,11 @@ systemd-analyze architectures uname
systemd-analyze smbios11
systemd-analyze smbios11 -q
+if test -f /sys/class/dmi/id/board_vendor && ! systemd-detect-virt --container ; then
+ systemd-analyze chid
+ systemd-analyze chid --json=pretty
+fi
+
systemd-analyze condition --instance=tmp --unit=systemd-growfs@.service
systemd-analyze verify --instance=tmp --man=no systemd-growfs@.service
systemd-analyze security --instance=tmp systemd-growfs@.service