mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 08:55:40 +03:00
Compare commits
18 Commits
b34363bc70
...
d2e628b91e
Author | SHA1 | Date | |
---|---|---|---|
|
d2e628b91e | ||
|
f7078de515 | ||
|
6d6048b4cb | ||
|
10a48938ef | ||
|
b58b13f1c6 | ||
|
c8f59296bf | ||
|
d585085f57 | ||
|
ff4b6a1915 | ||
|
d9f68f48f7 | ||
|
0310b2a60b | ||
|
115fac3c29 | ||
|
9d8f5e22f8 | ||
|
6fb0c52295 | ||
|
edd10ab29c | ||
|
988053eac3 | ||
|
a586f57eb2 | ||
|
e2e42056fd | ||
|
c2327afbfe |
8
TODO
8
TODO
@ -129,6 +129,11 @@ Deprecations and removals:
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* $LISTEN_PID, $MAINPID and $SYSTEMD_EXECPID env vars that the service manager
|
||||||
|
sets should be augmented with $LISTEN_PIDFDID, $MAINPIDFDID and
|
||||||
|
$SYSTEMD_EXECPIDFD (and similar for other env vars we might send). Also,
|
||||||
|
MAINPID= in sd_notify() should be augmented with MAINPIDFDID=, and so on.
|
||||||
|
|
||||||
* port copy.c over to use LabelOps for all labelling.
|
* port copy.c over to use LabelOps for all labelling.
|
||||||
|
|
||||||
* port remaining getmntent() users over to libmount. There are subtle
|
* port remaining getmntent() users over to libmount. There are subtle
|
||||||
@ -157,9 +162,6 @@ Features:
|
|||||||
sd_event_add_child(), and then get rid of many more explicit sigprocmask()
|
sd_event_add_child(), and then get rid of many more explicit sigprocmask()
|
||||||
calls.
|
calls.
|
||||||
|
|
||||||
* maybe set shell.prompt.prefix credential in run0 to some warning emoji,
|
|
||||||
i.e. ⚠️ or ☢️ or ⚡ or 👊 or 🧑🔧 or so.
|
|
||||||
|
|
||||||
* introduce new structure Tpm2CombinedPolicy, that combines the various TPm2
|
* introduce new structure Tpm2CombinedPolicy, that combines the various TPm2
|
||||||
policy bits into one structure, i.e. public key info, pcr masks, pcrlock
|
policy bits into one structure, i.e. public key info, pcr masks, pcrlock
|
||||||
stuff, pin and so on. Then pass that around in tpm2_seal() and tpm2_unseal().
|
stuff, pin and so on. Then pass that around in tpm2_seal() and tpm2_unseal().
|
||||||
|
@ -102,6 +102,7 @@ Some EFI variables control the loader or exported the loaders state to the start
|
|||||||
| EFI Variables |
|
| EFI Variables |
|
||||||
|---------------|------------------------|-------------------------------|
|
|---------------|------------------------|-------------------------------|
|
||||||
| LoaderEntryDefault | entry identifier to select as default at bootup | non-volatile |
|
| LoaderEntryDefault | entry identifier to select as default at bootup | non-volatile |
|
||||||
|
| LoaderEntryFallback | fallback entry identifier | non-volatile |
|
||||||
| LoaderConfigTimeout | timeout in seconds to show the menu | non-volatile |
|
| LoaderConfigTimeout | timeout in seconds to show the menu | non-volatile |
|
||||||
| LoaderEntryOneShot | entry identifier to select at the next and only the next bootup | non-volatile |
|
| LoaderEntryOneShot | entry identifier to select at the next and only the next bootup | non-volatile |
|
||||||
| LoaderDeviceIdentifier | list of identifiers of the volume the loader was started from | volatile |
|
| LoaderDeviceIdentifier | list of identifiers of the volume the loader was started from | volatile |
|
||||||
|
@ -58,6 +58,11 @@ variables. All EFI variables use the vendor UUID
|
|||||||
* The EFI variable `LoaderEntryDefault` contains the default boot loader entry
|
* The EFI variable `LoaderEntryDefault` contains the default boot loader entry
|
||||||
to use. It contains a NUL-terminated boot loader entry identifier.
|
to use. It contains a NUL-terminated boot loader entry identifier.
|
||||||
|
|
||||||
|
* The EFI variable `LoaderEntryFallback` contains the fallback boot loader entry
|
||||||
|
to use. Fallback boot entries can be used to ensure that a system starts even
|
||||||
|
if the default boot entry fails or other unexpected event happened (boot firmware
|
||||||
|
failure etc.). It contains a NUL-terminated boot loader entry identifier.
|
||||||
|
|
||||||
* Similarly, the EFI variable `LoaderEntryOneShot` contains the default boot
|
* Similarly, the EFI variable `LoaderEntryOneShot` contains the default boot
|
||||||
loader entry to use for a single following boot. It is set by the OS in order
|
loader entry to use for a single following boot. It is set by the OS in order
|
||||||
to request booting into a specific menu entry on the following boot. When set
|
to request booting into a specific menu entry on the following boot. When set
|
||||||
|
@ -146,8 +146,9 @@
|
|||||||
<option>@oneshot</option> or <option>@current</option>, which correspond to the current default boot loader
|
<option>@oneshot</option> or <option>@current</option>, which correspond to the current default boot loader
|
||||||
entry for all future boots, the current default boot loader entry for the next boot, and the currently booted
|
entry for all future boots, the current default boot loader entry for the next boot, and the currently booted
|
||||||
boot loader entry. These special IDs are resolved to the current values of the EFI variables
|
boot loader entry. These special IDs are resolved to the current values of the EFI variables
|
||||||
<varname>LoaderEntryDefault</varname>, <varname>LoaderEntryOneShot</varname> and <varname>LoaderEntrySelected</varname>,
|
<varname>LoaderEntryDefault</varname>, <varname>LoaderEntryFallback</varname>, <varname>LoaderEntryOneShot</varname>
|
||||||
see <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink> for details.
|
and <varname>LoaderEntrySelected</varname>, see <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">
|
||||||
|
Boot Loader Specification</ulink> for details.
|
||||||
These special IDs are primarily useful as a quick way to persistently make the currently booted boot loader
|
These special IDs are primarily useful as a quick way to persistently make the currently booted boot loader
|
||||||
entry the default choice, or to upgrade the default boot loader entry for the next boot to the default boot
|
entry the default choice, or to upgrade the default boot loader entry for the next boot to the default boot
|
||||||
loader entry for all future boots, but may be used for other operations too.</para>
|
loader entry for all future boots, but may be used for other operations too.</para>
|
||||||
|
52
man/run0.xml
52
man/run0.xml
@ -192,6 +192,35 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--pty</option></term>
|
||||||
|
<term><option>--pipe</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Request allocation of a pseudo TTY for the <command>run0</command> session (in case
|
||||||
|
of <option>--pty</option>), or request passing the caller's STDIO file descriptors directly through
|
||||||
|
(in case of <option>--pipe</option>). If neither switch is specified, or if both switches are
|
||||||
|
specified, the mode will be picked automatically: if standard input, standard output and standard
|
||||||
|
error output are all connected to a TTY then a pseudo TTY is allocated, otherwise the relevant file
|
||||||
|
descriptors are passed through directly.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--shell-prompt-prefix=<replaceable>STRING</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Set a shell prompt prefix string. This ultimately controls the
|
||||||
|
<varname>$SHELL_PROMPT_PREFIX</varname> environment variable for the invoked program, which is
|
||||||
|
typically imported into the shell prompt. By default – if emojis are supported – a superhero emoji is
|
||||||
|
shown (🦸). This default may also be changed (or turned off) by passing the
|
||||||
|
<varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable to <varname>run0</varname>,
|
||||||
|
see below. Set to an empty string to disable shell prompt prefixing.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--machine=</option></term>
|
<term><option>--machine=</option></term>
|
||||||
|
|
||||||
@ -256,7 +285,30 @@
|
|||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>$SHELL_PROMPT_PREFIX</varname></term>
|
||||||
|
<listitem><para>By default set to the superhero emoji (if supported), but may be overriden with the
|
||||||
|
<varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname> environment variable (see below), or the
|
||||||
|
<option>--shell-prompt-prefix=</option> switch (see above).</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
<para>The following variables may be passed to <command>run0</command>:</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>$SYSTEMD_RUN_SHELL_PROMPT_PREFIX</varname></term>
|
||||||
|
<listitem><para>If set, overrides the default shell prompt prefix that <command>run0</command> sets
|
||||||
|
for the invoked shell (the superhero emoji). Set to an empty string to disable shell prompt
|
||||||
|
prefixing.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
@ -451,6 +451,7 @@
|
|||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>LoaderEntryDefault</varname></term>
|
<term><varname>LoaderEntryDefault</varname></term>
|
||||||
|
<term><varname>LoaderEntryFallback</varname></term>
|
||||||
<term><varname>LoaderEntryOneShot</varname></term>
|
<term><varname>LoaderEntryOneShot</varname></term>
|
||||||
|
|
||||||
<listitem><para>The identifier of the default boot loader entry. Set primarily by the OS and read by the boot
|
<listitem><para>The identifier of the default boot loader entry. Set primarily by the OS and read by the boot
|
||||||
|
@ -80,6 +80,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||||||
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
|
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
|
||||||
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
|
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
|
||||||
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
|
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
|
||||||
|
[SPECIAL_GLYPH_SUPERHERO] = "S",
|
||||||
},
|
},
|
||||||
|
|
||||||
/* UTF-8 */
|
/* UTF-8 */
|
||||||
@ -149,6 +150,7 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||||||
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
|
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
|
||||||
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
|
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
|
||||||
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
|
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
|
||||||
|
[SPECIAL_GLYPH_SUPERHERO] = u8"🦸",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ typedef enum SpecialGlyph {
|
|||||||
SPECIAL_GLYPH_YELLOW_CIRCLE,
|
SPECIAL_GLYPH_YELLOW_CIRCLE,
|
||||||
SPECIAL_GLYPH_BLUE_CIRCLE,
|
SPECIAL_GLYPH_BLUE_CIRCLE,
|
||||||
SPECIAL_GLYPH_GREEN_CIRCLE,
|
SPECIAL_GLYPH_GREEN_CIRCLE,
|
||||||
|
SPECIAL_GLYPH_SUPERHERO,
|
||||||
_SPECIAL_GLYPH_MAX,
|
_SPECIAL_GLYPH_MAX,
|
||||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||||
} SpecialGlyph;
|
} SpecialGlyph;
|
||||||
|
@ -1019,6 +1019,7 @@ static int remove_loader_variables(void) {
|
|||||||
EFI_LOADER_VARIABLE(LoaderConfigTimeout),
|
EFI_LOADER_VARIABLE(LoaderConfigTimeout),
|
||||||
EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot),
|
EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot),
|
||||||
EFI_LOADER_VARIABLE(LoaderEntryDefault),
|
EFI_LOADER_VARIABLE(LoaderEntryDefault),
|
||||||
|
EFI_LOADER_VARIABLE(LoaderEntryFallback),
|
||||||
EFI_LOADER_VARIABLE(LoaderEntryLastBooted),
|
EFI_LOADER_VARIABLE(LoaderEntryLastBooted),
|
||||||
EFI_LOADER_VARIABLE(LoaderEntryOneShot),
|
EFI_LOADER_VARIABLE(LoaderEntryOneShot),
|
||||||
EFI_LOADER_VARIABLE(LoaderSystemToken)) {
|
EFI_LOADER_VARIABLE(LoaderSystemToken)) {
|
||||||
|
@ -88,6 +88,11 @@ static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
|
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
|
||||||
|
|
||||||
|
} else if (streq(arg1, "@fallback")) {
|
||||||
|
r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryFallback), NULL, (void *) ret_target, ret_target_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryFallback': %m");
|
||||||
|
|
||||||
} else if (arg1[0] == '@' && !streq(arg1, "@saved"))
|
} else if (arg1[0] == '@' && !streq(arg1, "@saved"))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
|
||||||
else {
|
else {
|
||||||
@ -139,6 +144,9 @@ int verb_set_efivar(int argc, char *argv[], void *userdata) {
|
|||||||
if (streq(argv[0], "set-default")) {
|
if (streq(argv[0], "set-default")) {
|
||||||
variable = EFI_LOADER_VARIABLE(LoaderEntryDefault);
|
variable = EFI_LOADER_VARIABLE(LoaderEntryDefault);
|
||||||
arg_parser = parse_loader_entry_target_arg;
|
arg_parser = parse_loader_entry_target_arg;
|
||||||
|
} else if (streq(argv[0], "set-fallback")) {
|
||||||
|
variable = EFI_LOADER_VARIABLE(LoaderEntryFallback);
|
||||||
|
arg_parser = parse_loader_entry_target_arg;
|
||||||
} else if (streq(argv[0], "set-oneshot")) {
|
} else if (streq(argv[0], "set-oneshot")) {
|
||||||
variable = EFI_LOADER_VARIABLE(LoaderEntryOneShot);
|
variable = EFI_LOADER_VARIABLE(LoaderEntryOneShot);
|
||||||
arg_parser = parse_loader_entry_target_arg;
|
arg_parser = parse_loader_entry_target_arg;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "proto/device-path.h"
|
#include "proto/device-path.h"
|
||||||
#include "proto/simple-text-io.h"
|
#include "proto/simple-text-io.h"
|
||||||
#include "random-seed.h"
|
#include "random-seed.h"
|
||||||
|
#include "recovery.h"
|
||||||
#include "sbat.h"
|
#include "sbat.h"
|
||||||
#include "secure-boot.h"
|
#include "secure-boot.h"
|
||||||
#include "shim.h"
|
#include "shim.h"
|
||||||
@ -88,6 +89,7 @@ typedef struct {
|
|||||||
uint64_t timeout_sec_config;
|
uint64_t timeout_sec_config;
|
||||||
uint64_t timeout_sec_efivar;
|
uint64_t timeout_sec_efivar;
|
||||||
char16_t *entry_default_config;
|
char16_t *entry_default_config;
|
||||||
|
char16_t *entry_fallback;
|
||||||
char16_t *entry_default_efivar;
|
char16_t *entry_default_efivar;
|
||||||
char16_t *entry_oneshot;
|
char16_t *entry_oneshot;
|
||||||
char16_t *entry_saved;
|
char16_t *entry_saved;
|
||||||
@ -97,6 +99,7 @@ typedef struct {
|
|||||||
bool auto_poweroff;
|
bool auto_poweroff;
|
||||||
bool auto_reboot;
|
bool auto_reboot;
|
||||||
bool reboot_for_bitlocker;
|
bool reboot_for_bitlocker;
|
||||||
|
bool fallback_firmware_failure;
|
||||||
secure_boot_enroll secure_boot_enroll;
|
secure_boot_enroll secure_boot_enroll;
|
||||||
bool force_menu;
|
bool force_menu;
|
||||||
bool use_saved_entry;
|
bool use_saved_entry;
|
||||||
@ -525,6 +528,8 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
|
|||||||
|
|
||||||
if (config->entry_default_config)
|
if (config->entry_default_config)
|
||||||
printf(" default (config): %ls\n", config->entry_default_config);
|
printf(" default (config): %ls\n", config->entry_default_config);
|
||||||
|
if (config->entry_fallback)
|
||||||
|
printf(" default (fallback): %ls\n", config->entry_fallback);
|
||||||
if (config->entry_default_efivar)
|
if (config->entry_default_efivar)
|
||||||
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
|
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
|
||||||
if (config->entry_oneshot)
|
if (config->entry_oneshot)
|
||||||
@ -538,6 +543,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
|
|||||||
printf(" auto-reboot: %ls\n", yes_no(config->auto_reboot));
|
printf(" auto-reboot: %ls\n", yes_no(config->auto_reboot));
|
||||||
printf(" beep: %ls\n", yes_no(config->beep));
|
printf(" beep: %ls\n", yes_no(config->beep));
|
||||||
printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
|
printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
|
||||||
|
printf(" fallback-firmware-failure: %ls\n", yes_no(config->fallback_firmware_failure));
|
||||||
|
|
||||||
switch (config->secure_boot_enroll) {
|
switch (config->secure_boot_enroll) {
|
||||||
case ENROLL_OFF:
|
case ENROLL_OFF:
|
||||||
@ -1275,6 +1281,10 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
|||||||
if (!parse_boolean(value, &config->reboot_for_bitlocker))
|
if (!parse_boolean(value, &config->reboot_for_bitlocker))
|
||||||
log_error("Error parsing 'reboot-for-bitlocker' config option, ignoring: %s",
|
log_error("Error parsing 'reboot-for-bitlocker' config option, ignoring: %s",
|
||||||
value);
|
value);
|
||||||
|
} else if (streq8(key, "fallback-firmware-failure")) {
|
||||||
|
if (!parse_boolean(value, &config->fallback_firmware_failure))
|
||||||
|
log_error("Error parsing 'fallback-firmware-failure' config option, ignoring: %s",
|
||||||
|
value);
|
||||||
|
|
||||||
} else if (streq8(key, "secure-boot-enroll")) {
|
} else if (streq8(key, "secure-boot-enroll")) {
|
||||||
if (streq8(value, "manual"))
|
if (streq8(value, "manual"))
|
||||||
@ -1634,8 +1644,10 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
|
|||||||
(void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", EFI_VARIABLE_NON_VOLATILE);
|
(void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", EFI_VARIABLE_NON_VOLATILE);
|
||||||
|
|
||||||
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", &config->entry_default_efivar);
|
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", &config->entry_default_efivar);
|
||||||
|
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryFallback", &config->entry_fallback);
|
||||||
|
|
||||||
strtolower16(config->entry_default_config);
|
strtolower16(config->entry_default_config);
|
||||||
|
strtolower16(config->entry_fallback);
|
||||||
strtolower16(config->entry_default_efivar);
|
strtolower16(config->entry_default_efivar);
|
||||||
strtolower16(config->entry_oneshot);
|
strtolower16(config->entry_oneshot);
|
||||||
strtolower16(config->entry_saved);
|
strtolower16(config->entry_saved);
|
||||||
@ -1777,11 +1789,29 @@ static size_t config_find_entry(Config *config, const char16_t *pattern) {
|
|||||||
return IDX_INVALID;
|
return IDX_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool config_is_fallback_required(Config *config) {
|
||||||
|
assert(config);
|
||||||
|
|
||||||
|
if (config->fallback_firmware_failure) {
|
||||||
|
return recovery_check_firmware_failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void config_select_default_entry(Config *config) {
|
static void config_select_default_entry(Config *config) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
assert(config);
|
assert(config);
|
||||||
|
|
||||||
|
if (config_is_fallback_required(config)) {
|
||||||
|
i = config_find_entry(config, config->entry_fallback);
|
||||||
|
if (i != IDX_INVALID) {
|
||||||
|
config->idx_default = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i = config_find_entry(config, config->entry_oneshot);
|
i = config_find_entry(config, config->entry_oneshot);
|
||||||
if (i != IDX_INVALID) {
|
if (i != IDX_INVALID) {
|
||||||
config->idx_default = i;
|
config->idx_default = i;
|
||||||
@ -2643,6 +2673,7 @@ static void config_free(Config *config) {
|
|||||||
boot_entry_free(config->entries[i]);
|
boot_entry_free(config->entries[i]);
|
||||||
free(config->entries);
|
free(config->entries);
|
||||||
free(config->entry_default_config);
|
free(config->entry_default_config);
|
||||||
|
free(config->entry_fallback);
|
||||||
free(config->entry_default_efivar);
|
free(config->entry_default_efivar);
|
||||||
free(config->entry_oneshot);
|
free(config->entry_oneshot);
|
||||||
free(config->entry_saved);
|
free(config->entry_saved);
|
||||||
|
@ -144,6 +144,16 @@ typedef struct {
|
|||||||
GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
|
GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
|
||||||
#define EFI_CUSTOM_MODE_ENABLE_GUID \
|
#define EFI_CUSTOM_MODE_ENABLE_GUID \
|
||||||
GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
|
GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
|
||||||
|
#define EFI_SYSTEM_RESOURCE_TABLE_GUID \
|
||||||
|
GUID_DEF(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80)
|
||||||
|
|
||||||
|
/* EFI System Resource Table (ESRT) Firmware Type Definitions */
|
||||||
|
#define ESRT_FW_TYPE_UNKNOWN 0x00000000
|
||||||
|
#define ESRT_FW_TYPE_SYSTEMFIRMWARE 0x00000001
|
||||||
|
#define ESRT_FW_TYPE_DEVICEFIRMWARE 0x00000002
|
||||||
|
#define ESRT_FW_TYPE_UEFIDRIVER 0x00000003
|
||||||
|
|
||||||
|
#define LAST_ATTEMPT_STATUS_SUCCESS 0x00000000
|
||||||
|
|
||||||
#define EVT_TIMER 0x80000000U
|
#define EVT_TIMER 0x80000000U
|
||||||
#define EVT_RUNTIME 0x40000000U
|
#define EVT_RUNTIME 0x40000000U
|
||||||
@ -458,6 +468,22 @@ typedef struct {
|
|||||||
} *ConfigurationTable;
|
} *ConfigurationTable;
|
||||||
} EFI_SYSTEM_TABLE;
|
} EFI_SYSTEM_TABLE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EFI_GUID FwClass;
|
||||||
|
uint32_t FwType;
|
||||||
|
uint32_t FwVersion;
|
||||||
|
uint32_t LowestSupportedFwVersion;
|
||||||
|
uint32_t CapsuleFlags;
|
||||||
|
uint32_t LastAttemptVersion;
|
||||||
|
uint32_t LastAttemptStatus;
|
||||||
|
} EFI_SYSTEM_RESOURCE_ENTRY;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t FwResourceCount;
|
||||||
|
uint32_t FwResourceCountMax;
|
||||||
|
uint64_t FwResourceVersion;
|
||||||
|
} EFI_SYSTEM_RESOURCE_TABLE;
|
||||||
|
|
||||||
extern EFI_SYSTEM_TABLE *ST;
|
extern EFI_SYSTEM_TABLE *ST;
|
||||||
extern EFI_BOOT_SERVICES *BS;
|
extern EFI_BOOT_SERVICES *BS;
|
||||||
extern EFI_RUNTIME_SERVICES *RT;
|
extern EFI_RUNTIME_SERVICES *RT;
|
||||||
|
@ -267,6 +267,7 @@ libefi_sources = files(
|
|||||||
'measure.c',
|
'measure.c',
|
||||||
'part-discovery.c',
|
'part-discovery.c',
|
||||||
'pe.c',
|
'pe.c',
|
||||||
|
'recovery.c',
|
||||||
'random-seed.c',
|
'random-seed.c',
|
||||||
'secure-boot.c',
|
'secure-boot.c',
|
||||||
'shim.c',
|
'shim.c',
|
||||||
|
23
src/boot/efi/recovery.c
Normal file
23
src/boot/efi/recovery.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "recovery.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define FALLBACK_BOOT_ENTRY L"ostree-1-lmp.conf\0"
|
||||||
|
|
||||||
|
bool recovery_check_firmware_failure(void) {
|
||||||
|
EFI_SYSTEM_RESOURCE_TABLE *esrt_table = NULL;
|
||||||
|
EFI_SYSTEM_RESOURCE_ENTRY *esrt_entry = NULL;
|
||||||
|
|
||||||
|
esrt_table = find_configuration_table(MAKE_GUID_PTR(EFI_SYSTEM_RESOURCE_TABLE));
|
||||||
|
if (esrt_table) {
|
||||||
|
esrt_entry = (void *)(esrt_table + 1);
|
||||||
|
for (uint32_t i = 0; i < esrt_table->FwResourceCount; i++, esrt_entry++) {
|
||||||
|
if (esrt_entry->FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) {
|
||||||
|
return (esrt_entry->LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
7
src/boot/efi/recovery.h
Normal file
7
src/boot/efi/recovery.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include "efivars-fundamental.h"
|
||||||
|
|
||||||
|
bool recovery_check_firmware_failure(void);
|
@ -8,7 +8,7 @@
|
|||||||
#include "operation.h"
|
#include "operation.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
|
|
||||||
static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_error *error) {
|
static int read_operation_errno(const siginfo_t *si, Operation *o) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(si);
|
assert(si);
|
||||||
@ -27,15 +27,6 @@ static int operation_done_internal(const siginfo_t *si, Operation *o, sd_bus_err
|
|||||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpectedly short message when reading operation's errno");
|
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpectedly short message when reading operation's errno");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o->done)
|
|
||||||
/* A completion routine is set for this operation, call it. */
|
|
||||||
return o->done(o, r, error);
|
|
||||||
|
|
||||||
/* The default operation when done is to simply return an error on failure or an empty success
|
|
||||||
* message on success. */
|
|
||||||
if (r < 0)
|
|
||||||
log_debug_errno(r, "Operation failed: %m");
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +42,18 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
|
|||||||
|
|
||||||
o->pid = 0;
|
o->pid = 0;
|
||||||
|
|
||||||
|
r = read_operation_errno(si, o);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Operation failed: %m");
|
||||||
|
|
||||||
|
/* If a completion routine (o->done) is set for this operation, call it. It sends a response, but can return an error in which case it expect us to reply.
|
||||||
|
* Otherwise, the default action is to simply return an error on failure or an empty success message on success. */
|
||||||
|
|
||||||
if (o->message) {
|
if (o->message) {
|
||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
if (o->done)
|
||||||
|
r = o->done(o, r, &error);
|
||||||
|
|
||||||
r = operation_done_internal(si, o, &error);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (!sd_bus_error_is_set(&error))
|
if (!sd_bus_error_is_set(&error))
|
||||||
sd_bus_error_set_errno(&error, r);
|
sd_bus_error_set_errno(&error, r);
|
||||||
@ -62,16 +61,20 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
|
|||||||
r = sd_bus_reply_method_error(o->message, &error);
|
r = sd_bus_reply_method_error(o->message, &error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to reply to dbus message: %m");
|
log_error_errno(r, "Failed to reply to dbus message: %m");
|
||||||
} else {
|
} else if (!o->done) {
|
||||||
|
/* when o->done set it's responsible for sending reply in a happy-path case */
|
||||||
r = sd_bus_reply_method_return(o->message, NULL);
|
r = sd_bus_reply_method_return(o->message, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to reply to dbus message: %m");
|
log_error_errno(r, "Failed to reply to dbus message: %m");
|
||||||
}
|
}
|
||||||
} else if (o->link) {
|
} else if (o->link) {
|
||||||
r = operation_done_internal(si, o, /* error = */ NULL);
|
if (o->done)
|
||||||
|
r = o->done(o, r, /* error = */ NULL);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
(void) sd_varlink_error_errno(o->link, r);
|
(void) sd_varlink_error_errno(o->link, r);
|
||||||
else
|
else if (!o->done)
|
||||||
|
/* when o->done set it's responsible for sending reply in a happy-path case */
|
||||||
(void) sd_varlink_reply(o->link, NULL);
|
(void) sd_varlink_reply(o->link, NULL);
|
||||||
} else
|
} else
|
||||||
assert_not_reached();
|
assert_not_reached();
|
||||||
|
@ -290,7 +290,7 @@ static int handle_arg_console(const char *arg) {
|
|||||||
else if (streq(arg, "passive"))
|
else if (streq(arg, "passive"))
|
||||||
arg_console_mode = CONSOLE_PASSIVE;
|
arg_console_mode = CONSOLE_PASSIVE;
|
||||||
else if (streq(arg, "pipe")) {
|
else if (streq(arg, "pipe")) {
|
||||||
if (isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO))
|
if (isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO))
|
||||||
log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE,
|
log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE,
|
||||||
"Console mode 'pipe' selected, but standard input/output are connected to an interactive TTY. "
|
"Console mode 'pipe' selected, but standard input/output are connected to an interactive TTY. "
|
||||||
"Most likely you want to use 'interactive' console mode for proper interactivity and shell job control. "
|
"Most likely you want to use 'interactive' console mode for proper interactivity and shell job control. "
|
||||||
@ -298,7 +298,7 @@ static int handle_arg_console(const char *arg) {
|
|||||||
|
|
||||||
arg_console_mode = CONSOLE_PIPE;
|
arg_console_mode = CONSOLE_PIPE;
|
||||||
} else if (streq(arg, "autopipe")) {
|
} else if (streq(arg, "autopipe")) {
|
||||||
if (isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO))
|
if (isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO))
|
||||||
arg_console_mode = CONSOLE_INTERACTIVE;
|
arg_console_mode = CONSOLE_INTERACTIVE;
|
||||||
else
|
else
|
||||||
arg_console_mode = CONSOLE_PIPE;
|
arg_console_mode = CONSOLE_PIPE;
|
||||||
@ -5981,7 +5981,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
umask(0022);
|
umask(0022);
|
||||||
|
|
||||||
if (arg_console_mode < 0)
|
if (arg_console_mode < 0)
|
||||||
arg_console_mode = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) ?
|
arg_console_mode = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) ?
|
||||||
CONSOLE_INTERACTIVE : CONSOLE_READ_ONLY;
|
CONSOLE_INTERACTIVE : CONSOLE_READ_ONLY;
|
||||||
|
|
||||||
if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
|
if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
|
||||||
|
381
src/run/run.c
381
src/run/run.c
@ -22,6 +22,7 @@
|
|||||||
#include "chase.h"
|
#include "chase.h"
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
|
#include "event-util.h"
|
||||||
#include "exec-util.h"
|
#include "exec-util.h"
|
||||||
#include "exit-status.h"
|
#include "exit-status.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
@ -85,6 +86,7 @@ static char *arg_exec_path = NULL;
|
|||||||
static bool arg_ignore_failure = false;
|
static bool arg_ignore_failure = false;
|
||||||
static char *arg_background = NULL;
|
static char *arg_background = NULL;
|
||||||
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
||||||
|
static char *arg_shell_prompt_prefix = NULL;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
||||||
@ -96,6 +98,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_working_directory, freep);
|
|||||||
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_shell_prompt_prefix, freep);
|
||||||
|
|
||||||
static int help(void) {
|
static int help(void) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
@ -171,6 +174,10 @@ static int help_sudo_mode(void) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
/* NB: Let's not go overboard with short options: we try to keep a modicum of compatibility with
|
||||||
|
* sudo's short switches, hence please do not introduce new short switches unless they have a roughly
|
||||||
|
* equivalent purpose on sudo. Use long options for everything private to run0. */
|
||||||
|
|
||||||
printf("%s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
printf("%s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
||||||
"\n%sElevate privileges interactively.%s\n\n"
|
"\n%sElevate privileges interactively.%s\n\n"
|
||||||
" -h --help Show this help\n"
|
" -h --help Show this help\n"
|
||||||
@ -188,6 +195,9 @@ static int help_sudo_mode(void) {
|
|||||||
" -D --chdir=PATH Set working directory\n"
|
" -D --chdir=PATH Set working directory\n"
|
||||||
" --setenv=NAME[=VALUE] Set environment variable\n"
|
" --setenv=NAME[=VALUE] Set environment variable\n"
|
||||||
" --background=COLOR Set ANSI color for background\n"
|
" --background=COLOR Set ANSI color for background\n"
|
||||||
|
" --pty Request allocation of a pseudo TTY for stdio\n"
|
||||||
|
" --pipe Request direct pipe for stdio\n"
|
||||||
|
" --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
|
||||||
"\nSee the %s for details.\n",
|
"\nSee the %s for details.\n",
|
||||||
program_invocation_short_name,
|
program_invocation_short_name,
|
||||||
ansi_highlight(),
|
ansi_highlight(),
|
||||||
@ -674,7 +684,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
/* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
|
/* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
|
||||||
* to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
|
* to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
|
||||||
* pipeline, but we are neatly interactive with tty-level isolation otherwise. */
|
* pipeline, but we are neatly interactive with tty-level isolation otherwise. */
|
||||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ?
|
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ?
|
||||||
ARG_STDIO_PTY :
|
ARG_STDIO_PTY :
|
||||||
ARG_STDIO_DIRECT;
|
ARG_STDIO_DIRECT;
|
||||||
|
|
||||||
@ -770,6 +780,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
ARG_NICE,
|
ARG_NICE,
|
||||||
ARG_SETENV,
|
ARG_SETENV,
|
||||||
ARG_BACKGROUND,
|
ARG_BACKGROUND,
|
||||||
|
ARG_PTY,
|
||||||
|
ARG_PIPE,
|
||||||
|
ARG_SHELL_PROMPT_PREFIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
||||||
@ -791,6 +804,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
{ "chdir", required_argument, NULL, 'D' },
|
{ "chdir", required_argument, NULL, 'D' },
|
||||||
{ "setenv", required_argument, NULL, ARG_SETENV },
|
{ "setenv", required_argument, NULL, ARG_SETENV },
|
||||||
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
||||||
|
{ "pty", no_argument, NULL, ARG_PTY },
|
||||||
|
{ "pipe", no_argument, NULL, ARG_PIPE },
|
||||||
|
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -883,6 +899,26 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_PTY:
|
||||||
|
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
|
||||||
|
arg_stdio = ARG_STDIO_AUTO;
|
||||||
|
else
|
||||||
|
arg_stdio = ARG_STDIO_PTY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_PIPE:
|
||||||
|
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
|
||||||
|
arg_stdio = ARG_STDIO_AUTO;
|
||||||
|
else
|
||||||
|
arg_stdio = ARG_STDIO_DIRECT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_SHELL_PROMPT_PREFIX:
|
||||||
|
r = free_and_strdup_warn(&arg_shell_prompt_prefix, optarg);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -913,7 +949,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
arg_wait = true;
|
arg_wait = true;
|
||||||
arg_aggressive_gc = true;
|
arg_aggressive_gc = true;
|
||||||
|
|
||||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO))
|
||||||
|
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
||||||
|
|
||||||
arg_expand_environment = false;
|
arg_expand_environment = false;
|
||||||
arg_send_sighup = true;
|
arg_send_sighup = true;
|
||||||
|
|
||||||
@ -993,6 +1031,25 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
|
log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!arg_shell_prompt_prefix) {
|
||||||
|
const char *e = secure_getenv("SYSTEMD_RUN_SHELL_PROMPT_PREFIX");
|
||||||
|
if (e) {
|
||||||
|
arg_shell_prompt_prefix = strdup(e);
|
||||||
|
if (!arg_shell_prompt_prefix)
|
||||||
|
return log_oom();
|
||||||
|
} else if (emoji_enabled()) {
|
||||||
|
arg_shell_prompt_prefix = strjoin(special_glyph(SPECIAL_GLYPH_SUPERHERO), " ");
|
||||||
|
if (!arg_shell_prompt_prefix)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isempty(arg_shell_prompt_prefix)) {
|
||||||
|
r = strv_env_assign(&arg_environment, "SHELL_PROMPT_PREFIX", arg_shell_prompt_prefix);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m");
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1181,7 +1238,7 @@ static int transient_service_set_properties(sd_bus_message *m, const char *pty_p
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
send_term = isatty_safe(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO);
|
send_term = isatty_safe(STDIN_FILENO) || isatty_safe(STDOUT_FILENO) || isatty_safe(STDERR_FILENO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_term) {
|
if (send_term) {
|
||||||
@ -1345,78 +1402,75 @@ static int transient_timer_set_properties(sd_bus_message *m) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
|
static int make_unit_name(UnitType t, char **ret) {
|
||||||
unsigned soft_reboots_count = 0;
|
|
||||||
const char *unique, *id;
|
|
||||||
char *p;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(bus);
|
|
||||||
assert(t >= 0);
|
assert(t >= 0);
|
||||||
assert(t < _UNIT_TYPE_MAX);
|
assert(t < _UNIT_TYPE_MAX);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
r = sd_bus_get_unique_name(bus, &unique);
|
/* Preferably use our PID + pidfd ID as identifier, if available. It's a boot time unique identifier
|
||||||
|
* managed by the kernel. Unfortunately only new kernels support this, hence we keep some fallback
|
||||||
|
* logic in place. */
|
||||||
|
|
||||||
|
_cleanup_(pidref_done) PidRef self = PIDREF_NULL;
|
||||||
|
r = pidref_set_self(&self);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to get reference to my own process: %m");
|
||||||
|
|
||||||
|
r = pidref_acquire_pidfd_id(&self);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to acquire pidfd ID of myself, defaulting to randomized unit name: %m");
|
||||||
|
|
||||||
|
/* We couldn't get the pidfd id. In that case, just pick a random uuid as name */
|
||||||
sd_id128_t rnd;
|
sd_id128_t rnd;
|
||||||
|
|
||||||
/* We couldn't get the unique name, which is a pretty
|
|
||||||
* common case if we are connected to systemd
|
|
||||||
* directly. In that case, just pick a random uuid as
|
|
||||||
* name */
|
|
||||||
|
|
||||||
r = sd_id128_randomize(&rnd);
|
r = sd_id128_randomize(&rnd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to generate random run unit name: %m");
|
return log_error_errno(r, "Failed to generate random run unit name: %m");
|
||||||
|
|
||||||
if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0)
|
r = asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t));
|
||||||
|
} else
|
||||||
|
r = asprintf(ret, "run-p" PID_FMT "-i%" PRIu64 ".%s", self.pid, self.fd_id, unit_type_to_string(t));
|
||||||
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We managed to get the unique name, then let's use that to name our transient units. */
|
static int connect_bus(sd_bus **ret) {
|
||||||
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
id = startswith(unique, ":1."); /* let' strip the usual prefix */
|
assert(ret);
|
||||||
if (!id)
|
|
||||||
id = startswith(unique, ":"); /* the spec only requires things to start with a colon, hence
|
|
||||||
* let's add a generic fallback for that. */
|
|
||||||
if (!id)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Unique name %s has unexpected format.",
|
|
||||||
unique);
|
|
||||||
|
|
||||||
/* The unique D-Bus names are actually unique per D-Bus instance, so on soft-reboot they will wrap
|
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
|
||||||
* and start over since the D-Bus broker is restarted. If there's a failed unit left behind that
|
* limited direct connection */
|
||||||
* hasn't been garbage collected, we'll conflict. Append the soft-reboot counter to avoid clashing. */
|
if (arg_wait ||
|
||||||
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
|
arg_stdio != ARG_STDIO_NONE ||
|
||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
|
||||||
r = bus_get_property_trivial(
|
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
|
||||||
bus, bus_systemd_mgr, "SoftRebootsCount", &error, 'u', &soft_reboots_count);
|
else
|
||||||
|
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug_errno(r,
|
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
|
||||||
"Failed to get SoftRebootsCount property, ignoring: %s",
|
|
||||||
bus_error_message(&error, r));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (soft_reboots_count > 0) {
|
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
||||||
if (asprintf(&p, "run-u%s-s%u.%s", id, soft_reboots_count, unit_type_to_string(t)) < 0)
|
|
||||||
return log_oom();
|
|
||||||
} else {
|
|
||||||
p = strjoin("run-u", id, ".", unit_type_to_string(t));
|
|
||||||
if (!p)
|
|
||||||
return log_oom();
|
|
||||||
}
|
|
||||||
|
|
||||||
*ret = p;
|
*ret = TAKE_PTR(bus);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct RunContext {
|
typedef struct RunContext {
|
||||||
sd_bus *bus;
|
|
||||||
sd_event *event;
|
sd_event *event;
|
||||||
PTYForward *forward;
|
PTYForward *forward;
|
||||||
sd_bus_slot *match;
|
char *service;
|
||||||
|
char *bus_path;
|
||||||
|
|
||||||
|
/* Bus objects */
|
||||||
|
sd_bus *bus;
|
||||||
|
sd_bus_slot *match_properties_changed;
|
||||||
|
sd_bus_slot *match_disconnected;
|
||||||
|
sd_event_source *retry_timer;
|
||||||
|
|
||||||
/* Current state of the unit */
|
/* Current state of the unit */
|
||||||
char *active_state;
|
char *active_state;
|
||||||
@ -1437,16 +1491,72 @@ typedef struct RunContext {
|
|||||||
uint32_t exit_status;
|
uint32_t exit_status;
|
||||||
} RunContext;
|
} RunContext;
|
||||||
|
|
||||||
static void run_context_free(RunContext *c) {
|
static int run_context_update(RunContext *c);
|
||||||
|
static int run_context_attach_bus(RunContext *c, sd_bus *bus);
|
||||||
|
static void run_context_detach_bus(RunContext *c);
|
||||||
|
static int run_context_reconnect(RunContext *c);
|
||||||
|
|
||||||
|
static void run_context_done(RunContext *c) {
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
|
run_context_detach_bus(c);
|
||||||
|
|
||||||
|
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
|
||||||
c->forward = pty_forward_free(c->forward);
|
c->forward = pty_forward_free(c->forward);
|
||||||
c->match = sd_bus_slot_unref(c->match);
|
|
||||||
c->bus = sd_bus_unref(c->bus);
|
|
||||||
c->event = sd_event_unref(c->event);
|
c->event = sd_event_unref(c->event);
|
||||||
|
|
||||||
free(c->active_state);
|
free(c->active_state);
|
||||||
free(c->result);
|
free(c->result);
|
||||||
|
free(c->bus_path);
|
||||||
|
free(c->service);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_retry_timer(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||||
|
RunContext *c = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
|
||||||
|
|
||||||
|
return run_context_reconnect(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int run_context_reconnect(RunContext *c) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
run_context_detach_bus(c);
|
||||||
|
|
||||||
|
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
||||||
|
r = connect_bus(&bus);
|
||||||
|
if (r < 0) {
|
||||||
|
log_warning_errno(r, "Failed to reconnect, retrying in 2s: %m");
|
||||||
|
|
||||||
|
r = event_reset_time_relative(
|
||||||
|
c->event,
|
||||||
|
&c->retry_timer,
|
||||||
|
CLOCK_MONOTONIC,
|
||||||
|
2 * USEC_PER_SEC, /* accuracy= */ 0,
|
||||||
|
on_retry_timer, c,
|
||||||
|
SD_EVENT_PRIORITY_NORMAL,
|
||||||
|
"retry-timeout",
|
||||||
|
/* force_reset= */ false);
|
||||||
|
if (r < 0) {
|
||||||
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||||
|
return log_error_errno(r, "Failed to install retry timer: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = run_context_attach_bus(c, bus);
|
||||||
|
if (r < 0) {
|
||||||
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Reconnected to bus.");
|
||||||
|
|
||||||
|
return run_context_update(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_context_check_done(RunContext *c) {
|
static void run_context_check_done(RunContext *c) {
|
||||||
@ -1454,16 +1564,13 @@ static void run_context_check_done(RunContext *c) {
|
|||||||
|
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
if (c->match)
|
|
||||||
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
|
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
|
||||||
else
|
|
||||||
done = true;
|
|
||||||
|
|
||||||
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
|
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
|
||||||
done = pty_forward_drain(c->forward);
|
done = pty_forward_drain(c->forward);
|
||||||
|
|
||||||
if (done)
|
if (done)
|
||||||
sd_event_exit(c->event, EXIT_SUCCESS);
|
(void) sd_event_exit(c->event, EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||||
@ -1480,7 +1587,7 @@ static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_er
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run_context_update(RunContext *c, const char *path) {
|
static int run_context_update(RunContext *c) {
|
||||||
|
|
||||||
static const struct bus_properties_map map[] = {
|
static const struct bus_properties_map map[] = {
|
||||||
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
|
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
|
||||||
@ -1503,16 +1610,35 @@ static int run_context_update(RunContext *c, const char *path) {
|
|||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = bus_map_all_properties(c->bus,
|
assert(c);
|
||||||
|
assert(c->bus);
|
||||||
|
|
||||||
|
r = bus_map_all_properties(
|
||||||
|
c->bus,
|
||||||
"org.freedesktop.systemd1",
|
"org.freedesktop.systemd1",
|
||||||
path,
|
c->bus_path,
|
||||||
map,
|
map,
|
||||||
BUS_MAP_STRDUP,
|
BUS_MAP_STRDUP,
|
||||||
&error,
|
&error,
|
||||||
NULL,
|
NULL,
|
||||||
c);
|
c);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
sd_event_exit(c->event, EXIT_FAILURE);
|
/* If this is a connection error, then try to reconnect. This might be because the service
|
||||||
|
* manager is being restarted. Handle this gracefully. */
|
||||||
|
if (sd_bus_error_has_names(
|
||||||
|
&error,
|
||||||
|
SD_BUS_ERROR_NO_REPLY,
|
||||||
|
SD_BUS_ERROR_DISCONNECTED,
|
||||||
|
SD_BUS_ERROR_TIMED_OUT,
|
||||||
|
SD_BUS_ERROR_SERVICE_UNKNOWN,
|
||||||
|
SD_BUS_ERROR_NAME_HAS_NO_OWNER)) {
|
||||||
|
|
||||||
|
log_info("Bus call failed due to connection problems. Trying to reconnect...");
|
||||||
|
/* Not propagating error, because we handled it already, by reconnecting. */
|
||||||
|
return run_context_reconnect(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||||
return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
|
return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1521,11 +1647,67 @@ static int run_context_update(RunContext *c, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||||
RunContext *c = ASSERT_PTR(userdata);
|
return run_context_update(ASSERT_PTR(userdata));
|
||||||
|
}
|
||||||
|
|
||||||
assert(m);
|
static int on_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||||
|
/* If our connection gets terminated, then try to reconnect. This might be because the service
|
||||||
|
* manager is being restarted. Handle this gracefully. */
|
||||||
|
log_info("Got disconnected from bus connection. Trying to reconnect...");
|
||||||
|
return run_context_reconnect(ASSERT_PTR(userdata));
|
||||||
|
}
|
||||||
|
|
||||||
return run_context_update(c, sd_bus_message_get_path(m));
|
static int run_context_attach_bus(RunContext *c, sd_bus *bus) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(c);
|
||||||
|
assert(bus);
|
||||||
|
|
||||||
|
assert(!c->bus);
|
||||||
|
assert(!c->match_properties_changed);
|
||||||
|
assert(!c->match_disconnected);
|
||||||
|
|
||||||
|
c->bus = sd_bus_ref(bus);
|
||||||
|
|
||||||
|
r = sd_bus_match_signal_async(
|
||||||
|
c->bus,
|
||||||
|
&c->match_properties_changed,
|
||||||
|
"org.freedesktop.systemd1",
|
||||||
|
c->bus_path,
|
||||||
|
"org.freedesktop.DBus.Properties",
|
||||||
|
"PropertiesChanged",
|
||||||
|
on_properties_changed, NULL, c);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to request PropertiesChanged signal match: %m");
|
||||||
|
|
||||||
|
r = sd_bus_match_signal_async(
|
||||||
|
bus,
|
||||||
|
&c->match_disconnected,
|
||||||
|
"org.freedesktop.DBus.Local",
|
||||||
|
/* path= */ NULL,
|
||||||
|
"org.freedesktop.DBus.Local",
|
||||||
|
"Disconnected",
|
||||||
|
on_disconnected, NULL, c);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to request Disconnected signal match: %m");
|
||||||
|
|
||||||
|
r = sd_bus_attach_event(c->bus, c->event, SD_EVENT_PRIORITY_NORMAL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_context_detach_bus(RunContext *c) {
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
if (c->bus) {
|
||||||
|
(void) sd_bus_detach_event(c->bus);
|
||||||
|
c->bus = sd_bus_unref(c->bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
c->match_properties_changed = sd_bus_slot_unref(c->match_properties_changed);
|
||||||
|
c->match_disconnected = sd_bus_slot_unref(c->match_disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
||||||
@ -1541,7 +1723,7 @@ static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
|||||||
/* If --wait is specified, we'll only exit the pty forwarding, but will continue to wait
|
/* If --wait is specified, we'll only exit the pty forwarding, but will continue to wait
|
||||||
* for the service to end. If the user hits ^C we'll exit too. */
|
* for the service to end. If the user hits ^C we'll exit too. */
|
||||||
} else if (rcode < 0) {
|
} else if (rcode < 0) {
|
||||||
sd_event_exit(c->event, EXIT_FAILURE);
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
||||||
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
|
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1818,7 +2000,7 @@ static int start_transient_service(sd_bus *bus) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to mangle unit name: %m");
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
||||||
} else {
|
} else {
|
||||||
r = make_unit_name(bus, UNIT_SERVICE, &service);
|
r = make_unit_name(UNIT_SERVICE, &service);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1860,7 +2042,7 @@ static int start_transient_service(sd_bus *bus) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
||||||
_cleanup_(run_context_free) RunContext c = {
|
_cleanup_(run_context_done) RunContext c = {
|
||||||
.cpu_usage_nsec = NSEC_INFINITY,
|
.cpu_usage_nsec = NSEC_INFINITY,
|
||||||
.memory_peak = UINT64_MAX,
|
.memory_peak = UINT64_MAX,
|
||||||
.memory_swap_peak = UINT64_MAX,
|
.memory_swap_peak = UINT64_MAX,
|
||||||
@ -1871,14 +2053,19 @@ static int start_transient_service(sd_bus *bus) {
|
|||||||
.inactive_exit_usec = USEC_INFINITY,
|
.inactive_exit_usec = USEC_INFINITY,
|
||||||
.inactive_enter_usec = USEC_INFINITY,
|
.inactive_enter_usec = USEC_INFINITY,
|
||||||
};
|
};
|
||||||
_cleanup_free_ char *path = NULL;
|
|
||||||
|
|
||||||
c.bus = sd_bus_ref(bus);
|
|
||||||
|
|
||||||
r = sd_event_default(&c.event);
|
r = sd_event_default(&c.event);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get event loop: %m");
|
return log_error_errno(r, "Failed to get event loop: %m");
|
||||||
|
|
||||||
|
c.service = strdup(service);
|
||||||
|
if (!c.service)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
c.bus_path = unit_dbus_path_from_name(service);
|
||||||
|
if (!c.bus_path)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
if (master >= 0) {
|
if (master >= 0) {
|
||||||
(void) sd_event_set_signal_exit(c.event, true);
|
(void) sd_event_set_signal_exit(c.event, true);
|
||||||
|
|
||||||
@ -1900,26 +2087,11 @@ static int start_transient_service(sd_bus *bus) {
|
|||||||
set_window_title(c.forward);
|
set_window_title(c.forward);
|
||||||
}
|
}
|
||||||
|
|
||||||
path = unit_dbus_path_from_name(service);
|
r = run_context_attach_bus(&c, bus);
|
||||||
if (!path)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = sd_bus_match_signal_async(
|
|
||||||
bus,
|
|
||||||
&c.match,
|
|
||||||
"org.freedesktop.systemd1",
|
|
||||||
path,
|
|
||||||
"org.freedesktop.DBus.Properties",
|
|
||||||
"PropertiesChanged",
|
|
||||||
on_properties_changed, NULL, &c);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to request properties changed signal match: %m");
|
return r;
|
||||||
|
|
||||||
r = sd_bus_attach_event(bus, c.event, SD_EVENT_PRIORITY_NORMAL);
|
r = run_context_update(&c);
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
|
||||||
|
|
||||||
r = run_context_update(&c, path);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2033,7 +2205,7 @@ static int start_transient_scope(sd_bus *bus) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to mangle scope name: %m");
|
return log_error_errno(r, "Failed to mangle scope name: %m");
|
||||||
} else {
|
} else {
|
||||||
r = make_unit_name(bus, UNIT_SCOPE, &scope);
|
r = make_unit_name(UNIT_SCOPE, &scope);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -2332,7 +2504,7 @@ static int start_transient_trigger(sd_bus *bus, const char *suffix) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
r = make_unit_name(bus, UNIT_SERVICE, &service);
|
r = make_unit_name(UNIT_SERVICE, &service);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2411,16 +2583,30 @@ static int run(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!arg_description) {
|
if (!arg_description) {
|
||||||
char *t;
|
_cleanup_free_ char *t = NULL;
|
||||||
|
|
||||||
if (strv_isempty(arg_cmdline))
|
if (strv_isempty(arg_cmdline))
|
||||||
t = strdup(arg_unit);
|
t = strdup(arg_unit);
|
||||||
else
|
else if (startswith(arg_cmdline[0], "-")) {
|
||||||
|
/* Drop the login shell marker from the command line when generating the description,
|
||||||
|
* in order to minimize user confusion. */
|
||||||
|
_cleanup_strv_free_ char **l = strv_copy(arg_cmdline);
|
||||||
|
if (!l)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = free_and_strdup_warn(l + 0, l[0] + 1);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
t = quote_command_line(l, SHELL_ESCAPE_EMPTY);
|
||||||
|
} else
|
||||||
t = quote_command_line(arg_cmdline, SHELL_ESCAPE_EMPTY);
|
t = quote_command_line(arg_cmdline, SHELL_ESCAPE_EMPTY);
|
||||||
if (!t)
|
if (!t)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
free_and_replace(arg_description, t);
|
arg_description = strjoin("[", program_invocation_short_name, "] ", t);
|
||||||
|
if (!arg_description)
|
||||||
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For backward compatibility reasons env var expansion is disabled by default for scopes, and
|
/* For backward compatibility reasons env var expansion is disabled by default for scopes, and
|
||||||
@ -2435,18 +2621,9 @@ static int run(int argc, char* argv[]) {
|
|||||||
" Use --expand-environment=yes/no to explicitly control it as needed.");
|
" Use --expand-environment=yes/no to explicitly control it as needed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
|
r = connect_bus(&bus);
|
||||||
* limited direct connection */
|
|
||||||
if (arg_wait ||
|
|
||||||
arg_stdio != ARG_STDIO_NONE ||
|
|
||||||
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
|
|
||||||
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
|
|
||||||
else
|
|
||||||
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
|
return r;
|
||||||
|
|
||||||
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
|
||||||
|
|
||||||
if (arg_scope)
|
if (arg_scope)
|
||||||
return start_transient_scope(bus);
|
return start_transient_scope(bus);
|
||||||
|
@ -1394,6 +1394,12 @@ static int boot_load_efi_entry_pointers(BootConfig *config, bool skip_efivars) {
|
|||||||
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
|
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
|
||||||
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\", ignoring: %m");
|
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\", ignoring: %m");
|
||||||
|
|
||||||
|
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryFallback), &config->entry_fallback);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
|
||||||
|
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryFallback\", ignoring: %m");
|
||||||
|
|
||||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntrySelected), &config->entry_selected);
|
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntrySelected), &config->entry_selected);
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
@ -71,6 +71,7 @@ typedef struct BootConfig {
|
|||||||
|
|
||||||
char *entry_oneshot;
|
char *entry_oneshot;
|
||||||
char *entry_default;
|
char *entry_default;
|
||||||
|
char *entry_fallback;
|
||||||
char *entry_selected;
|
char *entry_selected;
|
||||||
|
|
||||||
BootEntry *entries;
|
BootEntry *entries;
|
||||||
|
@ -82,7 +82,7 @@ TEST(keymaps) {
|
|||||||
|
|
||||||
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
|
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
|
||||||
TEST(dump_special_glyphs) {
|
TEST(dump_special_glyphs) {
|
||||||
assert_cc(SPECIAL_GLYPH_GREEN_CIRCLE + 1 == _SPECIAL_GLYPH_MAX);
|
assert_cc(SPECIAL_GLYPH_SUPERHERO + 1 == _SPECIAL_GLYPH_MAX);
|
||||||
|
|
||||||
log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
|
log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
|
||||||
|
|
||||||
@ -133,6 +133,7 @@ TEST(dump_special_glyphs) {
|
|||||||
dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE);
|
dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE);
|
||||||
dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE);
|
dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE);
|
||||||
dump_glyph(SPECIAL_GLYPH_GREEN_CIRCLE);
|
dump_glyph(SPECIAL_GLYPH_GREEN_CIRCLE);
|
||||||
|
dump_glyph(SPECIAL_GLYPH_SUPERHERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_INFO);
|
DEFINE_TEST_MAIN(LOG_INFO);
|
||||||
|
@ -261,4 +261,17 @@ if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; the
|
|||||||
assert_eq "$(run0 -D / pwd)" "/"
|
assert_eq "$(run0 -D / pwd)" "/"
|
||||||
assert_eq "$(run0 --user=testuser pwd)" "/home/testuser"
|
assert_eq "$(run0 --user=testuser pwd)" "/home/testuser"
|
||||||
assert_eq "$(run0 -D / --user=testuser pwd)" "/"
|
assert_eq "$(run0 -D / --user=testuser pwd)" "/"
|
||||||
|
|
||||||
|
# Verify that all combinations of --pty/--pipe come to the sam results
|
||||||
|
assert_eq "$(run0 echo -n foo)" "foo"
|
||||||
|
assert_eq "$(run0 --pty echo -n foo)" "foo"
|
||||||
|
assert_eq "$(run0 --pipe echo -n foo)" "foo"
|
||||||
|
assert_eq "$(run0 --pipe --pty echo -n foo)" "foo"
|
||||||
|
|
||||||
|
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
|
||||||
|
assert_neq "$(run0 --pty tty < /dev/null)" "not a tty"
|
||||||
|
assert_eq "$(run0 --pipe tty < /dev/null)" "not a tty"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)
|
||||||
|
assert_rc "37" systemd-run --unit=disconnecttest --wait --pipe --user -M testuser@.host bash -ec 'systemctl --user daemon-reexec; sleep 3; exit 37'
|
||||||
|
@ -39,6 +39,15 @@ assert_eq() {(
|
|||||||
fi
|
fi
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
assert_neq() {(
|
||||||
|
set +ex
|
||||||
|
|
||||||
|
if [[ "${1?}" = "${2?}" ]]; then
|
||||||
|
echo "FAIL: not expected: '$2' actual: '$1'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)}
|
||||||
|
|
||||||
assert_le() {(
|
assert_le() {(
|
||||||
set +ex
|
set +ex
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user