Add 'data' parameter to options and convert to programs where it is useful (#41786)
This commit is contained in:
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+61
-90
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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" },
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user