1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-21 13:34:21 +03:00

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.
This commit is contained in:
Lennart Poettering 2024-11-15 11:38:30 +01:00
parent a48803fd84
commit 8f114904fc
9 changed files with 277 additions and 2 deletions

View File

@ -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>

View File

@ -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'

224
src/analyze/analyze-chid.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int verb_chid(int argc, char *argv[], void *userdata);

View File

@ -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 },
{}
};

View File

@ -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',

View File

@ -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) |

View File

@ -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]);

View File

@ -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