Add 'data' parameter to options and convert to programs where it is useful (#41786)

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-04-23 21:13:32 +02:00
committed by GitHub
18 changed files with 965 additions and 1186 deletions
+6 -4
View File
@@ -2411,10 +2411,12 @@ SPDX-License-Identifier: LGPL-2.1-or-later
- **systemd-measure tool:**
- pre-calculate PCR 12 (command line) + PCR 13 (sysext) the same way we can precalculate PCR 11
- systemd-measure: add --pcrpkey-auto as an alternative to --pcrpkey=, where it
would just use the same public key specified with --public-key= (or the one
automatically derived from --private-key=).
- add --pcrpkey-auto as an alternative to --pcrpkey=, where it would just use
the same public key specified with --public-key= (or the one automatically
derived from --private-key=).
- allow multiple --initrd=, --efifw=, --dtbauto=, etc., params and pad and
concatenate the contents in the same way that ukify does, so we end up with
the expected measurement.
- systemd-mount should only consider modern file systems when mounting, similar
to systemd-dissect
+6 -16
View File
@@ -422,8 +422,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
OPTION_GROUP("Block Device Discovery Commands"):
break;
OPTION_GROUP("Block Device Discovery Commands"): {}
OPTION('p', "print-esp-path", NULL, "Print path to the EFI System Partition mount point"): {}
OPTION_LONG("print-path", NULL, /* help= */ NULL): /* Compatibility alias */
@@ -455,8 +454,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
arg_print_efi_architecture = true;
break;
OPTION_GROUP("Options"):
break;
OPTION_GROUP("Options"): {}
OPTION_COMMON_HELP:
return help();
@@ -605,16 +603,13 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
return r;
break;
OPTION_LONG("private-key", "PATH|URI",
"Private key for Secure Boot auto-enrollment"):
OPTION_COMMON_PRIVATE_KEY("Private key for Secure Boot auto-enrollment"):
r = free_and_strdup_warn(&arg_private_key, arg);
if (r < 0)
return r;
break;
OPTION_LONG("private-key-source", "SOURCE",
"Specify how to use the private key "
"(file, provider:PROVIDER, engine:ENGINE)"):
OPTION_COMMON_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(arg,
&arg_private_key_source,
&arg_private_key_source_type);
@@ -622,18 +617,13 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
return r;
break;
OPTION_LONG("certificate", "PATH|URI",
"PEM certificate to use when setting up Secure Boot auto-enrollment, "
"or a provider specific designation if --certificate-source= is used"):
OPTION_COMMON_CERTIFICATE("PEM certificate to use when setting up Secure Boot auto-enrollment"):
r = free_and_strdup_warn(&arg_certificate, arg);
if (r < 0)
return r;
break;
OPTION_LONG("certificate-source", "SOURCE",
"Specify how to interpret the certificate from --certificate=. "
"Allows the certificate to be loaded from an OpenSSL provider "
"(file, provider:PROVIDER)"):
OPTION_COMMON_CERTIFICATE_SOURCE:
r = parse_openssl_certificate_source_argument(arg,
&arg_certificate_source,
&arg_certificate_source_type);
+1 -1
View File
@@ -15,7 +15,7 @@ typedef enum UnifiedSection {
UNIFIED_SECTION_DTB,
UNIFIED_SECTION_UNAME,
UNIFIED_SECTION_SBAT,
UNIFIED_SECTION_PCRSIG,
UNIFIED_SECTION_PCRSIG, /* This is is not measured actually */
UNIFIED_SECTION_PCRPKEY,
UNIFIED_SECTION_PROFILE,
UNIFIED_SECTION_DTBAUTO,
+1 -2
View File
@@ -2348,8 +2348,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
/* The following all configure endpoint information explicitly */
OPTION_GROUP("Manual Endpoint Configuration"):
break;
OPTION_GROUP("Manual Endpoint Configuration"): {}
OPTION_LONG("vendor", "VENDOR", "Specify IMDS vendor literally"):
if (isempty(arg)) {
+40 -34
View File
@@ -1,15 +1,16 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <sys/epoll.h>
#include <unistd.h>
#include "devnum-util.h"
#include "fd-util.h"
#include "format-table.h"
#include "libudev-list-internal.h"
#include "log.h"
#include "main-func.h"
#include "libudev-util.h"
#include "options.h"
#include "string-util.h"
#include "tests.h"
#include "version.h"
@@ -404,52 +405,57 @@ static void test_list(void) {
assert_se(!udev_list_entry_get_by_name(e, "ccc"));
}
static int parse_args(int argc, char *argv[], const char **syspath, const char **subsystem) {
static const struct option options[] = {
{ "syspath", required_argument, NULL, 'p' },
{ "subsystem", required_argument, NULL, 's' },
{ "debug", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "monitor", no_argument, NULL, 'm' },
{}
};
int c;
static int help(void) {
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...]\n\n", program_invocation_short_name);
r = table_print_or_warn(options);
if (r < 0)
return r;
return 0;
}
static int parse_args(int argc, char *argv[], const char **syspath, const char **subsystem) {
assert(argc >= 0);
assert(argv);
assert(syspath);
assert(subsystem);
while ((c = getopt_long(argc, argv, "p:s:dhVm", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'p':
*syspath = optarg;
break;
case 's':
*subsystem = optarg;
break;
OPTION_COMMON_HELP:
return help();
case 'd':
log_set_max_level(LOG_DEBUG);
break;
case 'h':
printf("--debug --syspath= --subsystem= --help\n");
return 0;
case 'V':
OPTION('V', "version", NULL, "Show package version"):
printf("%s\n", GIT_VERSION);
return 0;
case 'm':
arg_monitor = true;
OPTION('p', "syspath", "PATH", "Syspath to test"):
*syspath = arg;
break;
case '?':
return -EINVAL;
OPTION('s', "subsystem", "SUBSYSTEM", "Subsystem to enumerate"):
*subsystem = arg;
break;
default:
assert_not_reached();
OPTION('d', "debug", NULL, "Enable debug logging"):
log_set_max_level(LOG_DEBUG);
break;
OPTION('m', "monitor", NULL, "Run monitor test"):
arg_monitor = true;
break;
}
return 1;
+339 -389
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <unistd.h>
#include "sd-json.h"
@@ -12,10 +11,12 @@
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "hexdecoct.h"
#include "log.h"
#include "main-func.h"
#include "openssl-util.h"
#include "options.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
@@ -65,71 +66,55 @@ STATIC_DESTRUCTOR_REGISTER(arg_sections, free_sections);
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *verbs = NULL, *options = NULL, *options2 = NULL;
int r;
r = terminal_urlify_man("systemd-measure", "1", &link);
if (r < 0)
return log_oom();
printf("%1$s [OPTIONS...] COMMAND ...\n"
"\n%5$sPre-calculate and sign PCR hash for a unified kernel image (UKI).%6$s\n"
"\n%3$sCommands:%4$s\n"
" status Show current PCR values\n"
" calculate Calculate expected PCR values\n"
" sign Calculate and sign expected PCR values\n"
" policy-digest Calculate expected TPM2 policy digests\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"
" --no-pager Do not pipe output into a pager\n"
" -c --current Use current PCR values\n"
" --phase=PHASE Specify a boot phase to sign for\n"
" --bank=DIGEST Select TPM bank (SHA1, SHA256, SHA384, SHA512)\n"
" --tpm2-device=PATH Use specified TPM2 device\n"
" --private-key=KEY Private key (PEM) to sign with\n"
" --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
" Specify how to use KEY for --private-key=. Allows\n"
" an OpenSSL engine/provider to be used for signing\n"
" --public-key=KEY Public key (PEM) to validate against\n"
" --certificate=PATH|URI\n"
" PEM certificate to use for signing, or a provider\n"
" specific designation if --certificate-source= is used\n"
" --certificate-source=file|provider:PROVIDER\n"
" Specify how to interpret the certificate from\n"
" --certificate=. Allows the certificate to be loaded\n"
" from an OpenSSL provider\n"
" --json=MODE Output as JSON\n"
" -j Same as --json=pretty on tty, --json=short otherwise\n"
" --append=PATH Load specified JSON signature, and append new signature to it\n"
"\n%3$sUKI PE Section Options:%4$s %3$sUKI PE Section%4$s\n"
" --linux=PATH Path to Linux kernel image file %7$s .linux\n"
" --osrel=PATH Path to os-release file %7$s .osrel\n"
" --cmdline=PATH Path to file with kernel command line %7$s .cmdline\n"
" --initrd=PATH Path to initrd image file %7$s .initrd\n"
" --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
" --dtbauto=PATH Path to DeviceTree file for auto selection %7$s .dtbauto\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
" --sbat=PATH Path to SBAT file %7$s .sbat\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"
" --profile=PATH Path to profile file %7$s .profile\n"
" --hwids=PATH Path to HWIDs file %7$s .hwids\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
ansi_underline(),
ansi_normal(),
ansi_highlight(),
ansi_normal(),
glyph(GLYPH_ARROW_RIGHT));
r = verbs_get_help_table(&verbs);
if (r < 0)
return r;
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
r = option_parser_get_help_table_group("UKI PE Section Options", &options2);
if (r < 0)
return r;
(void) table_sync_column_widths(0, verbs, options, options2);
printf("%s [OPTIONS...] COMMAND ...\n"
"\n%sPre-calculate and sign PCR hash for a unified kernel image (UKI).%s\n"
"\n%sCommands:%s\n",
program_invocation_short_name,
ansi_highlight(), ansi_normal(),
ansi_underline(), ansi_normal());
r = table_print_or_warn(verbs);
if (r < 0)
return r;
printf("\n%sOptions:%s\n", ansi_underline(), ansi_normal());
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\n%sUKI PE Section Options:%s\n", ansi_underline(), ansi_normal());
r = table_print_or_warn(options2);
if (r < 0)
return r;
printf("\nSee the %s for details.\n", link);
return 0;
}
static int verb_help(int argc, char *argv[], uintptr_t _data, void *userdata) {
return help();
}
VERB_COMMON_HELP_HIDDEN(help);
static char *normalize_phase(const char *s) {
_cleanup_strv_free_ char **l = NULL;
@@ -146,187 +131,39 @@ static char *normalize_phase(const char *s) {
return strv_join(strv_remove(l, ""), ":");
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
_ARG_SECTION_FIRST,
ARG_LINUX = _ARG_SECTION_FIRST,
ARG_OSREL,
ARG_CMDLINE,
ARG_INITRD,
ARG_UCODE,
ARG_SPLASH,
ARG_DTB,
ARG_UNAME,
ARG_SBAT,
_ARG_PCRSIG, /* the .pcrsig section is not input for signing, hence not actually an argument here */
ARG_PCRPKEY,
ARG_PROFILE,
ARG_DTBAUTO,
ARG_HWIDS,
_ARG_SECTION_LAST,
ARG_EFIFW = _ARG_SECTION_LAST,
ARG_BANK,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
ARG_PUBLIC_KEY,
ARG_CERTIFICATE,
ARG_CERTIFICATE_SOURCE,
ARG_TPM2_DEVICE,
ARG_JSON,
ARG_PHASE,
ARG_APPEND,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "version", no_argument, NULL, ARG_VERSION },
{ "linux", required_argument, NULL, ARG_LINUX },
{ "osrel", required_argument, NULL, ARG_OSREL },
{ "cmdline", required_argument, NULL, ARG_CMDLINE },
{ "initrd", required_argument, NULL, ARG_INITRD },
{ "ucode", required_argument, NULL, ARG_UCODE },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
{ "dtbauto", required_argument, NULL, ARG_DTBAUTO },
{ "uname", required_argument, NULL, ARG_UNAME },
{ "sbat", required_argument, NULL, ARG_SBAT },
{ "pcrpkey", required_argument, NULL, ARG_PCRPKEY },
{ "profile", required_argument, NULL, ARG_PROFILE },
{ "hwids", required_argument, NULL, ARG_HWIDS },
{ "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{ "public-key", required_argument, NULL, ARG_PUBLIC_KEY },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "certificate-source", required_argument, NULL, ARG_CERTIFICATE_SOURCE },
{ "json", required_argument, NULL, ARG_JSON },
{ "phase", required_argument, NULL, ARG_PHASE },
{ "append", required_argument, NULL, ARG_APPEND },
{}
};
int c, r;
static int parse_argv(int argc, char *argv[], char ***ret_args) {
assert(argc >= 0);
assert(argv);
assert(ret_args);
/* Make sure the arguments list and the section list, stays in sync */
assert_cc(_ARG_SECTION_FIRST + _UNIFIED_SECTION_MAX == _ARG_SECTION_LAST + 1);
OptionParser state = { argc, argv };
const Option *opt;
const char *arg;
int r;
while ((c = getopt_long(argc, argv, "hjc", options, NULL)) >= 0)
FOREACH_OPTION_FULL(&state, c, &opt, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_NO_PAGER:
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case _ARG_SECTION_FIRST..._ARG_SECTION_LAST: {
UnifiedSection section = c - _ARG_SECTION_FIRST;
r = parse_path_argument(optarg, /* suppress_root= */ false, arg_sections + section);
if (r < 0)
return r;
break;
}
case 'c':
OPTION('c', "current", NULL,
"Use current PCR values"):
arg_current = true;
break;
case ARG_BANK: {
const EVP_MD *implementation;
implementation = EVP_get_digestbyname(optarg);
if (!implementation)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown bank '%s', refusing.", optarg);
if (strv_extend(&arg_banks, EVP_MD_name(implementation)) < 0)
return log_oom();
break;
}
case ARG_PRIVATE_KEY:
r = free_and_strdup_warn(&arg_private_key, optarg);
if (r < 0)
return r;
break;
case ARG_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
optarg,
&arg_private_key_source,
&arg_private_key_source_type);
if (r < 0)
return r;
break;
case ARG_PUBLIC_KEY:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_public_key);
if (r < 0)
return r;
break;
case ARG_CERTIFICATE:
r = free_and_strdup_warn(&arg_certificate, optarg);
if (r < 0)
return r;
break;
case ARG_CERTIFICATE_SOURCE:
r = parse_openssl_certificate_source_argument(
optarg,
&arg_certificate_source,
&arg_certificate_source_type);
if (r < 0)
return r;
break;
case ARG_TPM2_DEVICE: {
_cleanup_free_ char *device = NULL;
if (streq(optarg, "list"))
return tpm2_list_devices(/* legend= */ true, /* quiet= */ false);
if (!streq(optarg, "auto")) {
device = strdup(optarg);
if (!device)
return log_oom();
}
free_and_replace(arg_tpm2_device, device);
break;
}
case 'j':
arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case ARG_PHASE: {
OPTION_LONG("phase", "PHASE",
"Specify a boot phase to sign for"): {
char *n;
n = normalize_phase(optarg);
n = normalize_phase(arg);
if (!n)
return log_oom();
@@ -337,18 +174,135 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_APPEND:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_append);
OPTION_LONG("bank", "DIGEST",
"Select TPM bank (SHA1, SHA256, SHA384, SHA512)"): {
const EVP_MD *implementation;
implementation = EVP_get_digestbyname(arg);
if (!implementation)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown bank '%s', refusing.", arg);
if (strv_extend(&arg_banks, EVP_MD_name(implementation)) < 0)
return log_oom();
break;
}
OPTION_LONG("tpm2-device", "PATH",
"Use specified TPM2 device"): {
_cleanup_free_ char *device = NULL;
if (streq(arg, "list"))
return tpm2_list_devices(/* legend= */ true, /* quiet= */ false);
if (!streq(arg, "auto")) {
device = strdup(arg);
if (!device)
return log_oom();
}
free_and_replace(arg_tpm2_device, device);
break;
}
OPTION_COMMON_PRIVATE_KEY("Private key (PEM) to sign with"):
r = free_and_strdup_warn(&arg_private_key, arg);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
OPTION_COMMON_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
arg,
&arg_private_key_source,
&arg_private_key_source_type);
if (r < 0)
return r;
default:
assert_not_reached();
break;
OPTION_LONG("public-key", "KEY",
"Public key (PEM) to validate against"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_public_key);
if (r < 0)
return r;
break;
OPTION_COMMON_CERTIFICATE("PEM certificate to use for signing"):
r = free_and_strdup_warn(&arg_certificate, arg);
if (r < 0)
return r;
break;
OPTION_COMMON_CERTIFICATE_SOURCE:
r = parse_openssl_certificate_source_argument(
arg,
&arg_certificate_source,
&arg_certificate_source_type);
if (r < 0)
return r;
break;
OPTION_COMMON_JSON:
r = parse_json_argument(arg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
OPTION_COMMON_LOWERCASE_J:
arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
break;
OPTION_LONG("append", "PATH",
"Load specified JSON signature, and append new signature to it"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_append);
if (r < 0)
return r;
break;
OPTION_GROUP("UKI PE Section Options"): {}
OPTION_LONG_DATA("linux", "PATH", UNIFIED_SECTION_LINUX,
"Path to Linux kernel image file (→ .linux)"): {}
OPTION_LONG_DATA("osrel", "PATH", UNIFIED_SECTION_OSREL,
"Path to os-release file (→ .osrel)"): {}
OPTION_LONG_DATA("cmdline", "PATH", UNIFIED_SECTION_CMDLINE,
"Path to file with kernel command line (→ .cmdline)"): {}
OPTION_LONG_DATA("initrd", "PATH", UNIFIED_SECTION_INITRD,
"Path to initrd image file (→ .initrd)"): {}
OPTION_LONG_DATA("ucode", "PATH", UNIFIED_SECTION_UCODE,
"Path to microcode image file (→ .ucode)"): {}
OPTION_LONG_DATA("splash", "PATH", UNIFIED_SECTION_SPLASH,
"Path to splash bitmap file (→ .splash)"): {}
OPTION_LONG_DATA("dtb", "PATH", UNIFIED_SECTION_DTB,
"Path to DeviceTree file (→ .dtb)"): {}
OPTION_LONG_DATA("dtbauto", "PATH", UNIFIED_SECTION_DTBAUTO,
"Path to DeviceTree file for auto selection (→ .dtbauto)"): {}
OPTION_LONG_DATA("uname", "PATH", UNIFIED_SECTION_UNAME,
"Path to 'uname -r' file (→ .uname)"): {}
OPTION_LONG_DATA("sbat", "PATH", UNIFIED_SECTION_SBAT,
"Path to SBAT file (→ .sbat)"): {}
/* The .pcrsig section is not input for signing, hence not actually an argument here */
OPTION_LONG_DATA("pcrpkey", "PATH", UNIFIED_SECTION_PCRPKEY,
"Path to public key for PCR signatures (→ .pcrpkey)"): {}
OPTION_LONG_DATA("profile", "PATH", UNIFIED_SECTION_PROFILE,
"Path to profile file (→ .profile)"): {}
OPTION_LONG_DATA("hwids", "PATH", UNIFIED_SECTION_HWIDS,
"Path to HWIDs file (→ .hwids)"): {}
OPTION_LONG_DATA("efifw", "PATH", UNIFIED_SECTION_EFIFW,
"Path to EFI firmware file (→ .efifw)"): {}
/* Make sure that if new sections are added, the list here is updated. */
assert_cc(UNIFIED_SECTION_EFIFW + 1 == _UNIFIED_SECTION_MAX);
assert(opt->data < _UNIFIED_SECTION_MAX);
r = parse_path_argument(arg, /* suppress_root= */ false, arg_sections + opt->data);
if (r < 0)
return r;
break;
}
if (arg_public_key && arg_certificate)
@@ -390,9 +344,160 @@ static int parse_argv(int argc, char *argv[]) {
return log_oom();
log_debug("Measuring boot phases: %s", j);
*ret_args = option_parser_get_args(&state);
return 1;
}
static int compare_reported_pcr_nr(uint32_t pcr, const char *varname, const char *description) {
_cleanup_free_ char *s = NULL;
uint32_t v;
int r;
r = efi_get_variable_string(varname, &s);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to read EFI variable '%s': %m", varname);
r = safe_atou32(s, &v);
if (r < 0)
return log_error_errno(r, "Failed to parse EFI variable '%s': %s", varname, s);
if (pcr != v)
log_warning("PCR number reported by stub for %s (%" PRIu32 ") different from our expectation (%" PRIu32 ").\n"
"The measurements are likely inconsistent.", description, v, pcr);
return 0;
}
static int validate_stub(void) {
uint64_t features;
bool found = false;
int r;
if (!tpm2_is_fully_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Sorry, system lacks full TPM2 support.");
r = efi_stub_get_features(&features);
if (r < 0)
return log_error_errno(r, "Unable to get stub features: %m");
if (!FLAGS_SET(features, EFI_STUB_FEATURE_THREE_PCRS))
log_warning("Warning: current kernel image does not support measuring itself, the command line or initrd system extension images.\n"
"The PCR measurements seen are unlikely to be valid.");
r = compare_reported_pcr_nr(TPM2_PCR_KERNEL_BOOT, EFI_LOADER_VARIABLE_STR("StubPcrKernelImage"), "kernel image");
if (r < 0)
return r;
STRV_FOREACH(bank, arg_banks) {
_cleanup_free_ char *b = NULL, *p = NULL;
b = strdup(*bank);
if (!b)
return log_oom();
if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/", ascii_strlower(b)) < 0)
return log_oom();
if (access(p, F_OK) < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to detect if '%s' exists: %m", b);
} else
found = true;
}
if (!found)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "None of the select PCR banks appear to exist.");
return 0;
}
VERB(verb_status, "status", NULL, VERB_ANY, 1, VERB_DEFAULT,
"Show current PCR values");
static int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
r = validate_stub();
if (r < 0)
return r;
STRV_FOREACH(bank, arg_banks) {
_cleanup_free_ char *b = NULL, *p = NULL, *s = NULL;
_cleanup_free_ void *h = NULL;
size_t l;
b = strdup(*bank);
if (!b)
return log_oom();
if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, ascii_strlower(b), (uint32_t) TPM2_PCR_KERNEL_BOOT) < 0)
return log_oom();
r = read_virtual_file(p, 4096, &s, NULL);
if (r == -ENOENT)
continue;
if (r < 0)
return log_error_errno(r, "Failed to read '%s': %m", p);
r = unhexmem(strstrip(s), &h, &l);
if (r < 0)
return log_error_errno(r, "Failed to decode PCR value '%s': %m", s);
if (!sd_json_format_enabled(arg_json_format_flags)) {
_cleanup_free_ char *f = hexmem(h, l);
if (!f)
return log_oom();
if (bank == arg_banks) {
/* before the first line for each PCR, write a short descriptive text to
* stderr, and leave the primary content on stdout */
fflush(stdout);
fprintf(stderr, "%s# PCR[%" PRIu32 "] %s%s%s\n",
ansi_grey(),
(uint32_t) TPM2_PCR_KERNEL_BOOT,
tpm2_pcr_index_to_string(TPM2_PCR_KERNEL_BOOT),
memeqzero(h, l) ? " (NOT SET!)" : "",
ansi_normal());
fflush(stderr);
}
printf("%" PRIu32 ":%s=%s\n", (uint32_t) TPM2_PCR_KERNEL_BOOT, b, f);
} else {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *bv = NULL, *a = NULL;
r = sd_json_buildo(
&bv,
SD_JSON_BUILD_PAIR_INTEGER("pcr", TPM2_PCR_KERNEL_BOOT),
SD_JSON_BUILD_PAIR_HEX("hash", h, l));
if (r < 0)
return log_error_errno(r, "Failed to build JSON object: %m");
a = sd_json_variant_ref(sd_json_variant_by_key(v, b));
r = sd_json_variant_append_array(&a, bv);
if (r < 0)
return log_error_errno(r, "Failed to append PCR entry to JSON array: %m");
r = sd_json_variant_set_field(&v, b, a);
if (r < 0)
return log_error_errno(r, "Failed to add bank info to object: %m");
}
}
if (sd_json_format_enabled(arg_json_format_flags)) {
if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
pager_open(arg_pager_flags);
sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
}
return 0;
}
/* The PCR 11 state for one specific bank */
typedef struct PcrState {
char *bank;
@@ -711,6 +816,8 @@ static void pcr_states_restore(PcrState *pcr_states, size_t n) {
}
}
VERB_NOARG(verb_calculate, "calculate",
"Calculate expected PCR values");
static int verb_calculate(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL;
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
@@ -992,186 +1099,29 @@ static int build_policy_digest(bool sign) {
return 0;
}
VERB_NOARG(verb_sign, "sign",
"Calculate and sign expected PCR values");
static int verb_sign(int argc, char *argv[], uintptr_t _data, void *userdata) {
return build_policy_digest(/* sign= */ true);
}
VERB_NOARG(verb_policy_digest, "policy-digest",
"Calculate expected TPM2 policy digests");
static int verb_policy_digest(int argc, char *argv[], uintptr_t _data, void *userdata) {
return build_policy_digest(/* sign= */ false);
}
static int compare_reported_pcr_nr(uint32_t pcr, const char *varname, const char *description) {
_cleanup_free_ char *s = NULL;
uint32_t v;
int r;
r = efi_get_variable_string(varname, &s);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to read EFI variable '%s': %m", varname);
r = safe_atou32(s, &v);
if (r < 0)
return log_error_errno(r, "Failed to parse EFI variable '%s': %s", varname, s);
if (pcr != v)
log_warning("PCR number reported by stub for %s (%" PRIu32 ") different from our expectation (%" PRIu32 ").\n"
"The measurements are likely inconsistent.", description, v, pcr);
return 0;
}
static int validate_stub(void) {
uint64_t features;
bool found = false;
int r;
if (!tpm2_is_fully_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Sorry, system lacks full TPM2 support.");
r = efi_stub_get_features(&features);
if (r < 0)
return log_error_errno(r, "Unable to get stub features: %m");
if (!FLAGS_SET(features, EFI_STUB_FEATURE_THREE_PCRS))
log_warning("Warning: current kernel image does not support measuring itself, the command line or initrd system extension images.\n"
"The PCR measurements seen are unlikely to be valid.");
r = compare_reported_pcr_nr(TPM2_PCR_KERNEL_BOOT, EFI_LOADER_VARIABLE_STR("StubPcrKernelImage"), "kernel image");
if (r < 0)
return r;
STRV_FOREACH(bank, arg_banks) {
_cleanup_free_ char *b = NULL, *p = NULL;
b = strdup(*bank);
if (!b)
return log_oom();
if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/", ascii_strlower(b)) < 0)
return log_oom();
if (access(p, F_OK) < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to detect if '%s' exists: %m", b);
} else
found = true;
}
if (!found)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "None of the select PCR banks appear to exist.");
return 0;
}
static int verb_status(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
r = validate_stub();
if (r < 0)
return r;
STRV_FOREACH(bank, arg_banks) {
_cleanup_free_ char *b = NULL, *p = NULL, *s = NULL;
_cleanup_free_ void *h = NULL;
size_t l;
b = strdup(*bank);
if (!b)
return log_oom();
if (asprintf(&p, "/sys/class/tpm/tpm0/pcr-%s/%" PRIu32, ascii_strlower(b), (uint32_t) TPM2_PCR_KERNEL_BOOT) < 0)
return log_oom();
r = read_virtual_file(p, 4096, &s, NULL);
if (r == -ENOENT)
continue;
if (r < 0)
return log_error_errno(r, "Failed to read '%s': %m", p);
r = unhexmem(strstrip(s), &h, &l);
if (r < 0)
return log_error_errno(r, "Failed to decode PCR value '%s': %m", s);
if (!sd_json_format_enabled(arg_json_format_flags)) {
_cleanup_free_ char *f = NULL;
f = hexmem(h, l);
if (!h)
return log_oom();
if (bank == arg_banks) {
/* before the first line for each PCR, write a short descriptive text to
* stderr, and leave the primary content on stdout */
fflush(stdout);
fprintf(stderr, "%s# PCR[%" PRIu32 "] %s%s%s\n",
ansi_grey(),
(uint32_t) TPM2_PCR_KERNEL_BOOT,
tpm2_pcr_index_to_string(TPM2_PCR_KERNEL_BOOT),
memeqzero(h, l) ? " (NOT SET!)" : "",
ansi_normal());
fflush(stderr);
}
printf("%" PRIu32 ":%s=%s\n", (uint32_t) TPM2_PCR_KERNEL_BOOT, b, f);
} else {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *bv = NULL, *a = NULL;
r = sd_json_buildo(
&bv,
SD_JSON_BUILD_PAIR_INTEGER("pcr", TPM2_PCR_KERNEL_BOOT),
SD_JSON_BUILD_PAIR_HEX("hash", h, l));
if (r < 0)
return log_error_errno(r, "Failed to build JSON object: %m");
a = sd_json_variant_ref(sd_json_variant_by_key(v, b));
r = sd_json_variant_append_array(&a, bv);
if (r < 0)
return log_error_errno(r, "Failed to append PCR entry to JSON array: %m");
r = sd_json_variant_set_field(&v, b, a);
if (r < 0)
return log_error_errno(r, "Failed to add bank info to object: %m");
}
}
if (sd_json_format_enabled(arg_json_format_flags)) {
if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
pager_open(arg_pager_flags);
sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
}
return 0;
}
static int measure_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, verb_help },
{ "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
{ "calculate", VERB_ANY, 1, 0, verb_calculate },
{ "policy-digest", VERB_ANY, 1, 0, verb_policy_digest },
{ "sign", VERB_ANY, 1, 0, verb_sign },
{}
};
return dispatch_verb(argc, argv, verbs, NULL);
}
static int run(int argc, char *argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
return measure_main(argc, argv);
return dispatch_verb_with_args(args, NULL);
}
DEFINE_MAIN_FUNCTION(run);
+31 -33
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <sys/stat.h>
#include "alloc-util.h"
@@ -8,15 +7,18 @@
#include "creds-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "format-table.h"
#include "fs-util.h"
#include "generator.h"
#include "log.h"
#include "main-func.h"
#include "mkdir.h"
#include "network-generator.h"
#include "options.h"
#include "path-util.h"
#include "proc-cmdline.h"
#include "string-util.h"
#include "strv.h"
#define NETWORK_UNIT_DIRECTORY "/run/systemd/network/"
@@ -148,52 +150,47 @@ static int context_save(Context *context) {
}
static int help(void) {
printf("%s [OPTIONS...] [-- KERNEL_CMDLINE]\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --root=PATH Operate on an alternate filesystem root\n",
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...] [-- KERNEL_CMDLINE]\n\n",
program_invocation_short_name);
r = table_print_or_warn(options);
if (r < 0)
return r;
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_ROOT,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "root", required_argument, NULL, ARG_ROOT },
{},
};
int c;
static int parse_argv(int argc, char *argv[], char ***ret_args) {
assert(argc >= 0);
assert(argv);
assert(ret_args);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_ROOT:
arg_root = optarg;
OPTION_LONG("root", "PATH",
"Operate on an alternate filesystem root"):
arg_root = arg;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
*ret_args = option_parser_get_args(&state);
return 1;
}
@@ -205,20 +202,21 @@ static int run(int argc, char *argv[]) {
umask(0022);
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
if (optind >= argc) {
if (strv_isempty(args)) {
r = proc_cmdline_parse(parse_cmdline_item, &context, 0);
if (r < 0)
return log_warning_errno(r, "Failed to parse kernel command line: %m");
} else {
for (int i = optind; i < argc; i++) {
STRV_FOREACH(a, args) {
_cleanup_free_ char *word = NULL;
char *value;
word = strdup(argv[i]);
word = strdup(*a);
if (!word)
return log_oom();
+306 -426
View File
File diff suppressed because it is too large Load Diff
+61 -90
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -11,12 +10,14 @@
#include "efi-fundamental.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "fs-util.h"
#include "install-file.h"
#include "io-util.h"
#include "log.h"
#include "main-func.h"
#include "openssl-util.h"
#include "options.h"
#include "parse-argument.h"
#include "pe-binary.h"
#include "pretty-print.h"
@@ -47,119 +48,96 @@ STATIC_DESTRUCTOR_REGISTER(arg_signed_data_signature, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL, *verbs = NULL;
int r;
r = terminal_urlify_man("systemd-sbsign", "1", &link);
if (r < 0)
return log_oom();
printf("%1$s [OPTIONS...] COMMAND ...\n"
"\n%5$sSign binaries for EFI Secure Boot%6$s\n"
"\n%3$sCommands:%4$s\n"
" sign EXEFILE Sign the given binary for EFI Secure Boot\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"
" --output Where to write the signed PE binary\n"
" --certificate=PATH|URI\n"
" PEM certificate to use for signing, or a provider\n"
" specific designation if --certificate-source= is used\n"
" --certificate-source=file|provider:PROVIDER\n"
" Specify how to interpret the certificate from\n"
" --certificate=. Allows the certificate to be loaded\n"
" from an OpenSSL provider\n"
" --private-key=KEY Private key (PEM) to sign with\n"
" --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
" Specify how to use KEY for --private-key=. Allows\n"
" an OpenSSL engine/provider to be used for signing\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
ansi_underline(),
ansi_normal(),
ansi_highlight(),
ansi_normal());
r = verbs_get_help_table(&verbs);
if (r < 0)
return r;
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
(void) table_sync_column_widths(0, verbs, options);
printf("%s [OPTIONS...] COMMAND ...\n"
"\n%sSign binaries for EFI Secure Boot%s\n"
"\n%sCommands:%s\n",
program_invocation_short_name,
ansi_highlight(), ansi_normal(),
ansi_underline(), ansi_normal());
r = table_print_or_warn(verbs);
if (r < 0)
return r;
printf("\n%sOptions:%s\n", ansi_underline(), ansi_normal());
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\nSee the %s for details.\n", link);
return 0;
}
static int verb_help(int argc, char *argv[], uintptr_t _data, void *userdata) {
return help();
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_OUTPUT,
ARG_CERTIFICATE,
ARG_CERTIFICATE_SOURCE,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
ARG_PREPARE_OFFLINE_SIGNING,
ARG_SIGNED_DATA,
ARG_SIGNED_DATA_SIGNATURE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "output", required_argument, NULL, ARG_OUTPUT },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "certificate-source", required_argument, NULL, ARG_CERTIFICATE_SOURCE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{ "prepare-offline-signing", no_argument, NULL, ARG_PREPARE_OFFLINE_SIGNING },
{ "signed-data", required_argument, NULL, ARG_SIGNED_DATA },
{ "signed-data-signature", required_argument, NULL, ARG_SIGNED_DATA_SIGNATURE },
{}
};
int c, r;
VERB_COMMON_HELP_HIDDEN(help);
static int parse_argv(int argc, char *argv[], char ***ret_args) {
assert(argc >= 0);
assert(argv);
assert(ret_args);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_OUTPUT:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_output);
OPTION_LONG("output", "PATH",
"Where to write the signed PE binary"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_output);
if (r < 0)
return r;
break;
case ARG_CERTIFICATE:
r = free_and_strdup_warn(&arg_certificate, optarg);
OPTION_COMMON_CERTIFICATE("PEM certificate to use for signing"):
r = free_and_strdup_warn(&arg_certificate, arg);
if (r < 0)
return r;
break;
case ARG_CERTIFICATE_SOURCE:
OPTION_COMMON_CERTIFICATE_SOURCE:
r = parse_openssl_certificate_source_argument(
optarg,
arg,
&arg_certificate_source,
&arg_certificate_source_type);
if (r < 0)
return r;
break;
case ARG_PRIVATE_KEY:
r = free_and_strdup_warn(&arg_private_key, optarg);
OPTION_COMMON_PRIVATE_KEY("Private key (PEM) to sign with"):
r = free_and_strdup_warn(&arg_private_key, arg);
if (r < 0)
return r;
break;
case ARG_PRIVATE_KEY_SOURCE:
OPTION_COMMON_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
optarg,
arg,
&arg_private_key_source,
&arg_private_key_source_type);
if (r < 0)
@@ -167,29 +145,23 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_PREPARE_OFFLINE_SIGNING:
OPTION_LONG("prepare-offline-signing", NULL, /* help= */ NULL):
arg_prepare_offline_signing = true;
break;
case ARG_SIGNED_DATA:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_signed_data);
OPTION_LONG("signed-data", "PATH", /* help= */ NULL):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_signed_data);
if (r < 0)
return r;
break;
case ARG_SIGNED_DATA_SIGNATURE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_signed_data_signature);
OPTION_LONG("signed-data-signature", "PATH", /* help= */ NULL):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_signed_data_signature);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (arg_private_key_source && !arg_certificate)
@@ -201,6 +173,7 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_prepare_offline_signing && (arg_private_key || arg_signed_data || arg_signed_data_signature))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--prepare-offline-signing cannot be used with --private-key=, --signed-data= or --signed-data-signature=");
*ret_args = option_parser_get_args(&state);
return 1;
}
@@ -442,6 +415,8 @@ static int pkcs7_add_digest_attribute(PKCS7 *p7, BIO *data, PKCS7_SIGNER_INFO *s
return 0;
}
VERB(verb_sign, "sign", "EXEFILE", 2, 2, 0,
"Sign the given binary for EFI Secure Boot");
static int verb_sign(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
@@ -742,20 +717,16 @@ static int verb_sign(int argc, char *argv[], uintptr_t _data, void *userdata) {
}
static int run(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, verb_help },
{ "sign", 2, 2, 0, verb_sign },
{}
};
int r;
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
return dispatch_verb(argc, argv, verbs, NULL);
return dispatch_verb_with_args(args, NULL);
}
DEFINE_MAIN_FUNCTION(run);
+22 -3
View File
@@ -19,10 +19,11 @@ typedef struct Option {
char short_code;
const char *long_code;
const char *metavar;
uintptr_t data;
const char *help;
} Option;
#define _OPTION(counter, fl, sc, lc, mv, h) \
#define _OPTION(counter, fl, sc, lc, mv, d, h) \
_section_("SYSTEMD_OPTIONS") \
_alignptr_ \
_used_ \
@@ -35,6 +36,7 @@ typedef struct Option {
.short_code = sc, \
.long_code = lc, \
.metavar = mv, \
.data = d, \
.help = h, \
}; \
case (0x100 + counter)
@@ -43,14 +45,17 @@ typedef struct Option {
* The define is structured as 'case' so that it can be followed by ':' and indented appropriately.
*/
#define OPTION_GROUP(gr) \
_OPTION(__COUNTER__, OPTION_GROUP_MARKER, /* sc= */ 0, /* lc= */ gr, /* mv= */ NULL, /* h= */ NULL)
_OPTION(__COUNTER__, OPTION_GROUP_MARKER, /* sc= */ 0, /* lc= */ gr, /* mv= */ NULL, /* d= */ 0u, /* h= */ NULL)
#define OPTION_FULL(fl, sc, lc, mv, h) _OPTION(__COUNTER__, fl, sc, lc, mv, h)
#define OPTION_FULL_DATA(fl, sc, lc, mv, d, h) _OPTION(__COUNTER__, fl, sc, lc, mv, d, h)
#define OPTION_FULL(fl, sc, lc, mv, h) OPTION_FULL_DATA(fl, sc, lc, mv, /* d= */ 0u, h)
#define OPTION(sc, lc, mv, h) OPTION_FULL(/* fl= */ 0, sc, lc, mv, h)
#define OPTION_LONG(lc, mv, h) OPTION(/* sc= */ 0, lc, mv, h)
#define OPTION_LONG_FLAGS(fl, lc, mv, h) OPTION_FULL(fl, /* sc= */ 0, lc, mv, h)
#define OPTION_LONG_DATA(lc, mv, d, h) OPTION_FULL_DATA(/* fl= */ 0, /* sc= */ 0, lc, mv, d, h)
#define OPTION_SHORT(sc, mv, h) OPTION(sc, /* lc= */ NULL, mv, h)
#define OPTION_SHORT_FLAGS(fl, sc, mv, h) OPTION_FULL(fl, sc, /* lc= */ NULL, mv, h)
#define OPTION_SHORT_DATA(sc, mv, d, h) OPTION_FULL_DATA(/* fl= */ 0, sc, /* lc= */ NULL, mv, d, h)
#define OPTION_POSITIONAL OPTION_FULL(OPTION_POSITIONAL_ENTRY, /* sc= */ 0, "(positional)", /* mv= */ NULL, /* h= */ NULL)
#define OPTION_HELP_VERBATIM(lc, h) OPTION_FULL(OPTION_HELP_ENTRY_VERBATIM, /* sc= */ 0, lc, /* mv= */ NULL, h)
@@ -89,6 +94,20 @@ typedef struct Option {
#define OPTION_COMMON_LOWERCASE_J \
OPTION_SHORT('j', NULL, \
"Equivalent to --json=pretty (on TTY) or --json=short (otherwise)")
#define OPTION_COMMON_PRIVATE_KEY(purpose) \
OPTION_LONG("private-key", "PATH|URI", purpose)
#define OPTION_COMMON_PRIVATE_KEY_SOURCE \
OPTION_LONG("private-key-source", "SOURCE", \
"Specify how to use the private key " \
"(file, provider:PROVIDER, engine:ENGINE)")
#define OPTION_COMMON_CERTIFICATE(purpose) \
OPTION_LONG("certificate", "PATH|URI", purpose \
", or a provider-specific designation if --certificate-source= is used")
#define OPTION_COMMON_CERTIFICATE_SOURCE \
OPTION_LONG("certificate-source", "SOURCE", \
"Specify how to interpret the certificate from --certificate=. " \
"Allows the certificate to be loaded from an OpenSSL provider " \
"(file, provider:PROVIDER)")
/* This is magically mapped to the beginning and end of the section */
extern const Option __start_SYSTEMD_OPTIONS[];
+40 -56
View File
@@ -3,7 +3,6 @@
Copyright © 2010 ProFUSION embedded systems
***/
#include <getopt.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/mount.h>
@@ -29,10 +28,10 @@
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
#include "getopt-defs.h"
#include "initrd-util.h"
#include "killall.h"
#include "log.h"
#include "options.h"
#include "parse-util.h"
#include "pidref.h"
#include "printk-util.h"
@@ -58,103 +57,88 @@ static uint8_t arg_exit_code = 0;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
static int parse_argv(int argc, char *argv[]) {
enum {
COMMON_GETOPT_ARGS,
SHUTDOWN_GETOPT_ARGS,
};
static const struct option options[] = {
COMMON_GETOPT_OPTIONS,
SHUTDOWN_GETOPT_OPTIONS,
{}
};
int c, r;
assert(argc >= 1);
assert(argv);
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
optind = 0;
/* The interface is: the verb must stay in argv[1]. Any extra positional arguments
* are warned about and ignored. See 4b5d8d0f22ae61ceb45a25391354ba53b43ee992. */
/* "-" prevents getopt from permuting argv[] and moving the verb away
* from argv[1]. Our interface to initrd promises it'll be there. */
while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
OptionParser state = { argc, argv, OPTION_PARSER_RETURN_POSITIONAL_ARGS };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case ARG_LOG_LEVEL:
r = log_set_max_level_from_string(optarg);
OPTION_COMMON_LOG_LEVEL:
r = log_set_max_level_from_string(arg);
if (r < 0)
log_warning_errno(r, "Failed to parse log level %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse log level %s, ignoring: %m", arg);
break;
case ARG_LOG_TARGET:
r = log_set_target_from_string(optarg);
OPTION_COMMON_LOG_TARGET:
r = log_set_target_from_string(arg);
if (r < 0)
log_warning_errno(r, "Failed to parse log target %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse log target %s, ignoring: %m", arg);
break;
case ARG_LOG_COLOR:
if (optarg) {
r = log_show_color_from_string(optarg);
OPTION_LONG_FLAGS(OPTION_OPTIONAL_ARG, "log-color", "BOOL",
"Highlight important messages"):
if (arg) {
r = log_show_color_from_string(arg);
if (r < 0)
log_warning_errno(r, "Failed to parse log color setting %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse log color setting %s, ignoring: %m", arg);
} else
log_show_color(true);
break;
case ARG_LOG_LOCATION:
if (optarg) {
r = log_show_location_from_string(optarg);
OPTION_LONG_FLAGS(OPTION_OPTIONAL_ARG, "log-location", "BOOL",
"Include code location in messages"):
if (arg) {
r = log_show_location_from_string(arg);
if (r < 0)
log_warning_errno(r, "Failed to parse log location setting %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse log location setting %s, ignoring: %m", arg);
} else
log_show_location(true);
break;
case ARG_LOG_TIME:
if (optarg) {
r = log_show_time_from_string(optarg);
OPTION_LONG_FLAGS(OPTION_OPTIONAL_ARG, "log-time", "BOOL",
"Prefix messages with current time"):
if (arg) {
r = log_show_time_from_string(arg);
if (r < 0)
log_warning_errno(r, "Failed to parse log time setting %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse log time setting %s, ignoring: %m", arg);
} else
log_show_time(true);
break;
case ARG_EXIT_CODE:
r = safe_atou8(optarg, &arg_exit_code);
OPTION_LONG("exit-code", "N",
"Exit code for reboot/kexec"):
r = safe_atou8(arg, &arg_exit_code);
if (r < 0)
log_warning_errno(r, "Failed to parse exit code %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse exit code %s, ignoring: %m", arg);
break;
case ARG_TIMEOUT:
r = parse_sec(optarg, &arg_timeout);
OPTION_LONG("timeout", "TIME",
"Overall shutdown timeout"):
r = parse_sec(arg, &arg_timeout);
if (r < 0)
log_warning_errno(r, "Failed to parse shutdown timeout %s, ignoring: %m", optarg);
log_warning_errno(r, "Failed to parse shutdown timeout %s, ignoring: %m", arg);
break;
case '\001':
OPTION_POSITIONAL:
if (!arg_verb)
arg_verb = optarg;
arg_verb = arg;
else
log_warning("Got extraneous arguments, ignoring.");
log_warning("Got extraneous argument, ignoring.");
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (!arg_verb)
+31 -48
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <poll.h>
#include <unistd.h>
@@ -11,9 +10,11 @@
#include "bus-internal.h"
#include "bus-util.h"
#include "errno-util.h"
#include "format-table.h"
#include "io-util.h"
#include "log.h"
#include "main-func.h"
#include "options.h"
#include "parse-argument.h"
#include "time-util.h"
@@ -23,84 +24,66 @@ static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
static bool arg_quiet = false;
static int help(void) {
printf("%s [OPTIONS...]\n\n"
"Forward messages between a pipe or socket and a D-Bus bus.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -p --bus-path=PATH Path to the bus address (default: %s)\n"
" --system Connect to system bus\n"
" --user Connect to user bus\n"
" -M --machine=CONTAINER Name of local container to connect to\n"
" -q --quiet Fail silently instead of logging errors\n",
program_invocation_short_name, DEFAULT_SYSTEM_BUS_ADDRESS);
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...]\n"
"\nForward messages between a pipe or socket and a D-Bus bus.\n\n",
program_invocation_short_name);
r = table_print_or_warn(options);
if (r < 0)
return r;
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_USER,
ARG_SYSTEM,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "bus-path", required_argument, NULL, 'p' },
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "machine", required_argument, NULL, 'M' },
{ "quiet", no_argument, NULL, 'q' },
{},
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hp:M:", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_USER:
OPTION_LONG("user", NULL, "Connect to user bus"):
arg_runtime_scope = RUNTIME_SCOPE_USER;
break;
case ARG_SYSTEM:
OPTION_LONG("system", NULL, "Connect to system bus"):
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
break;
case 'p':
arg_bus_path = optarg;
OPTION('p', "bus-path", "PATH",
"Path to the bus address (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")"):
arg_bus_path = arg;
break;
case 'M':
r = parse_machine_argument(optarg, &arg_bus_path, &arg_transport);
OPTION_COMMON_MACHINE:
r = parse_machine_argument(arg, &arg_bus_path, &arg_transport);
if (r < 0)
return r;
break;
case 'q':
OPTION('q', "quiet", NULL, "Fail silently instead of logging errors"):
arg_quiet = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (argc > optind)
if (option_parser_get_n_args(&state) > 0)
return log_full_errno(arg_quiet ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(EINVAL),
"%s takes no arguments.",
program_invocation_short_name);
+1 -2
View File
@@ -2121,8 +2121,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
OPTION_COMMON_VERSION:
return version();
OPTION_GROUP("Options"):
break;
OPTION_GROUP("Options"): {}
OPTION_LONG("root", "PATH", "Operate on an alternate filesystem root"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_root);
+50 -58
View File
@@ -1,84 +1,75 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "chase.h"
#include "fd-util.h"
#include "format-table.h"
#include "log.h"
#include "main-func.h"
#include "options.h"
#include "strv.h"
#include "tests.h"
static char *arg_root = NULL;
static const char *arg_root = NULL;
static int arg_flags = 0;
static bool arg_open = false;
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_ROOT = 0x1000,
ARG_OPEN,
};
static int help(void) {
_cleanup_(table_unrefp) Table *options = NULL;
int r;
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "root", required_argument, NULL, ARG_ROOT },
{ "open", no_argument, NULL, ARG_OPEN },
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
{ "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT },
{ "nonexistent", no_argument, NULL, CHASE_NONEXISTENT },
{ "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS },
{ "trigger-autofs", no_argument, NULL, CHASE_TRIGGER_AUTOFS },
{ "safe", no_argument, NULL, CHASE_SAFE },
{ "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH },
{ "step", no_argument, NULL, CHASE_STEP },
{ "nofollow", no_argument, NULL, CHASE_NOFOLLOW },
{ "warn", no_argument, NULL, CHASE_WARN },
{}
};
printf("%s [OPTIONS...] path...\n"
"\nExercise chase() function on specified paths.\n\n",
program_invocation_short_name);
int c;
r = table_print_or_warn(options);
if (r < 0)
return r;
assert_se(argc >= 0);
assert_se(argv);
return 0;
}
while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
static int parse_argv(int argc, char *argv[], char ***ret_args) {
assert(argc >= 0);
assert(argv);
assert(ret_args);
OptionParser state = { argc, argv };
const Option *opt;
const char *arg;
FOREACH_OPTION_FULL(&state, c, &opt, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
printf("Syntax:\n"
" %s [OPTION...] path...\n"
"Options:\n"
, argv[0]);
FOREACH_ARRAY(option, options, ELEMENTSOF(options) - 1)
printf(" --%s\n", option->name);
return 0;
OPTION_COMMON_HELP:
return help();
case ARG_ROOT:
arg_root = optarg;
OPTION_LONG("root", "PATH", "Operate below specified root directory"):
arg_root = arg;
break;
case ARG_OPEN:
OPTION_LONG("open", NULL, "Open the resolved path"):
arg_open = true;
break;
case CHASE_PREFIX_ROOT:
case CHASE_NONEXISTENT:
case CHASE_NO_AUTOFS:
case CHASE_TRIGGER_AUTOFS:
case CHASE_SAFE:
case CHASE_TRAIL_SLASH:
case CHASE_STEP:
case CHASE_NOFOLLOW:
case CHASE_WARN:
arg_flags |= c;
OPTION_LONG_DATA("prefix-root", NULL, CHASE_PREFIX_ROOT, "Prefix path with --root"): {}
OPTION_LONG_DATA("nonexistent", NULL, CHASE_NONEXISTENT, "Allow path to not exist"): {}
OPTION_LONG_DATA("no-autofs", NULL, CHASE_NO_AUTOFS, "Return -EREMOTE if autofs mount point found"): {}
OPTION_LONG_DATA("trigger-autofs", NULL, CHASE_TRIGGER_AUTOFS, "Trigger autofs mounts"): {}
OPTION_LONG_DATA("safe", NULL, CHASE_SAFE, "Refuse privilege boundary crossings"): {}
OPTION_LONG_DATA("trail-slash", NULL, CHASE_TRAIL_SLASH, "Preserve trailing slash"): {}
OPTION_LONG_DATA("step", NULL, CHASE_STEP, "Execute a single normalization step"): {}
OPTION_LONG_DATA("nofollow", NULL, CHASE_NOFOLLOW, "Do not follow the path's right-most component"): {}
OPTION_LONG_DATA("warn", NULL, CHASE_WARN, "Emit a warning on error"):
arg_flags |= opt->data;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (optind == argc)
*ret_args = option_parser_get_args(&state);
if (strv_isempty(*ret_args))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "At least one argument is required.");
return 1;
@@ -89,18 +80,19 @@ static int run(int argc, char **argv) {
test_setup_logging(LOG_DEBUG);
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
for (int i = optind; i < argc; i++) {
STRV_FOREACH(a, args) {
_cleanup_free_ char *p = NULL;
_cleanup_close_ int fd = -EBADF;
printf("%s ", argv[i]);
printf("%s ", *a);
fflush(stdout);
r = chase(argv[i], arg_root, arg_flags, &p, arg_open ? &fd : NULL);
r = chase(*a, arg_root, arg_flags, &p, arg_open ? &fd : NULL);
if (r < 0)
log_error_errno(r, "failed: %m");
else {
+13 -2
View File
@@ -772,6 +772,12 @@ static void test_macros_parse_one(
if (entries[i].short_code != 0)
ASSERT_EQ(opt->short_code, entries[i].short_code);
ASSERT_TRUE(streq_ptr(arg, entries[i].argument));
if (streq_ptr(entries[i].long_code, "optional2"))
ASSERT_EQ(opt->data, 666u);
else
ASSERT_EQ(opt->data, 0u);
i++;
switch (c) {
@@ -796,13 +802,16 @@ static void test_macros_parse_one(
OPTION_FULL(OPTION_OPTIONAL_ARG, 'o', "optional", "ARG", "Optional arg option"):
break;
/* OPTION_FULL_DATA: optional arg */
OPTION_FULL_DATA(OPTION_OPTIONAL_ARG, 'O', "optional2", "ARG", 666, "Optional arg option"):
break;
/* OPTION_FULL: stops parsing */
OPTION_FULL(OPTION_STOPS_PARSING, 0, "exec", NULL, "Stop parsing after this"):
break;
/* OPTION_GROUP: group marker (never returned by parser) */
OPTION_GROUP("Advanced"):
break;
OPTION_GROUP("Advanced"): {}
/* OPTION_LONG: long only, in the "Advanced" group */
OPTION_LONG("debug", NULL, "Enable debug mode"):
@@ -1015,6 +1024,7 @@ TEST(option_macros) {
"-v",
"--required=rval",
"--optional=oval",
"--optional2=oval",
"--debug",
"pos2",
"-o",
@@ -1025,6 +1035,7 @@ TEST(option_macros) {
{ .short_code = 'v' },
{ "required", "rval" },
{ "optional", "oval" },
{ "optional2", "oval" },
{ "debug" },
{ "optional", NULL },
{ "help" },
+1 -2
View File
@@ -4225,8 +4225,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
OPTION_COMMON_VERSION:
return version();
OPTION_GROUP("Options"):
break;
OPTION_GROUP("Options"): {}
OPTION_LONG("user", NULL, "Execute user configuration"):
arg_runtime_scope = RUNTIME_SCOPE_USER;
+10 -20
View File
@@ -361,8 +361,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_runtime_scope = RUNTIME_SCOPE_USER;
break;
OPTION_GROUP("Image"):
break;
OPTION_GROUP("Image"): {}
OPTION('D', "directory", "PATH", "Root directory for the VM"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_directory);
@@ -395,8 +394,7 @@ static int parse_argv(int argc, char *argv[]) {
"Invalid image disk type: %s", arg);
break;
OPTION_GROUP("Host Configuration"):
break;
OPTION_GROUP("Host Configuration"): {}
OPTION_LONG("cpus", "CPUS", "Configure number of CPUs in guest"): {}
OPTION_LONG("qemu-smp", "CPUS", /* help= */ NULL): /* Compat alias */
@@ -657,8 +655,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(r, "Failed to parse --grow-image= parameter: %s", arg);
break;
OPTION_GROUP("Execution"):
break;
OPTION_GROUP("Execution"): {}
OPTION('s', "smbios11", "STRING", "Pass an arbitrary SMBIOS Type #11 string to the VM"):
if (isempty(arg)) {
@@ -679,8 +676,7 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
OPTION_GROUP("System Identity"):
break;
OPTION_GROUP("System Identity"): {}
OPTION('M', "machine", "NAME", "Set the machine name for the VM"):
if (isempty(arg))
@@ -704,8 +700,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(r, "Invalid UUID: %s", arg);
break;
OPTION_GROUP("Properties"):
break;
OPTION_GROUP("Properties"): {}
OPTION('S', "slice", "SLICE", "Place the VM in the specified slice"): {
_cleanup_free_ char *mangled = NULL;
@@ -734,8 +729,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_keep_unit = true;
break;
OPTION_GROUP("User Namespacing"):
break;
OPTION_GROUP("User Namespacing"): {}
OPTION_LONG("private-users", "UIDBASE[:NUIDS]",
"Configure the UID/GID range to map into the virtiofsd namespace"):
@@ -744,8 +738,7 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
OPTION_GROUP("Mounts"):
break;
OPTION_GROUP("Mounts"): {}
OPTION_LONG("bind", "SOURCE[:TARGET]", "Mount a file or directory from the host into the VM"): {}
OPTION_LONG("bind-ro", "SOURCE[:TARGET]", "Mount a file or directory, but read-only"): {
@@ -837,8 +830,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_oom();
break;
OPTION_GROUP("Integration"):
break;
OPTION_GROUP("Integration"): {}
OPTION_LONG("forward-journal", "FILE|DIR", "Forward the VM's journal to the host"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_forward_journal);
@@ -890,8 +882,7 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
OPTION_GROUP("Input/Output"):
break;
OPTION_GROUP("Input/Output"): {}
OPTION_LONG("console", "MODE",
"Console mode (interactive, native, gui, read-only or headless)"):
@@ -916,8 +907,7 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
OPTION_GROUP("Credentials"):
break;
OPTION_GROUP("Credentials"): {}
OPTION_LONG("set-credential", "ID:VALUE", "Pass a credential with literal value to the VM"):
r = machine_credential_set(&arg_credentials, arg);
+6
View File
@@ -45,6 +45,12 @@ cat >/tmp/result.json <<EOF
EOF
"$SD_MEASURE" calculate --linux=/tmp/tpmdata1 --initrd=/tmp/tpmdata2 --bank=sha1 --bank=sha256 --bank=sha384 --bank=sha512 --phase=foo -j | diff -u - /tmp/result.json
cat >/tmp/result <<EOF
11:sha1=8a625cbc3c497b9a86dcf4f6a32582895ce969bb
EOF
"$SD_MEASURE" calculate \
--{linux,osrel,cmdline,initrd,ucode,splash,dtb,dtbauto,uname,sbat,pcrpkey,profile,hwids,efifw}=/tmp/tpmdata1 \
--bank=sha1 --phase=foo | cmp - /tmp/result
rm /tmp/result /tmp/result.json
# Generate key pair