1
0
mirror of https://github.com/systemd/systemd synced 2026-03-28 09:44:50 +01:00

Compare commits

...

23 Commits

Author SHA1 Message Date
Yu Watanabe
73bf0f2ace
Merge pull request #20738 from mrc0mmand/ci-llvm-13
ci: build with clang-13
2021-09-16 09:32:21 +09:00
Lennart Poettering
28078aa5cc
Merge pull request #20483 from medhefgo/boot
sd-boot: Add support for changing console mode at runtime
2021-09-16 00:03:41 +02:00
Lennart Poettering
46ebc0a6f5
Merge pull request #20731 from a-wai/main
hostnamed: add support for getting the chassis type from device-tree
2021-09-16 00:02:05 +02:00
Lennart Poettering
3d7e273dba
Merge pull request #20746 from poettering/sysctl-rework
various sysctl-util.c cleanups
2021-09-16 00:01:18 +02:00
Luca Boccassi
a51f6dba60
Merge pull request #20751 from poettering/watchdog-tweaklet
two minor watchdog tweaklets
2021-09-15 21:48:39 +01:00
Arnaud Ferraris
e6e6ca8251 hostnamed: add support for getting the chassis type from device-tree
Device-tree based devices can't get the chassis type from DMI or ACPI,
and so far need a custom `/etc/machine-info` to set this property right.

A new 'chassis-type' toplevel device tree property has recently been
approved into the DT specification, making it possible to automate
chassis type detection on such devices.

This patch therefore falls back to reading this device-tree property if
nothing is available through both DMI and ACPI.

Signed-off-by: Arnaud Ferraris <arnaud.ferraris@collabora.com>
2021-09-15 16:46:07 +02:00
Arnaud Ferraris
533f11c529 basic: nulstr-util: add nulstr_get() returning the matching string
Currently `nulstr_contains` returns a boolean, making it difficult to
identify which of the input strings matches the "needle".

Adding a new `nulstr_get()` function, returning a const pointer to the
matching string, eases this process and allows us to directly re-use the
result of a call to this function without additional processing or
memory allocation.

Signed-off-by: Arnaud Ferraris <arnaud.ferraris@collabora.com>
2021-09-15 16:45:58 +02:00
Lennart Poettering
3448711b7e test: add test case for sysctl-util.[ch] 2021-09-15 16:32:40 +02:00
Lennart Poettering
89edc243e4 test: make array in test-sysctl fully read-only 2021-09-15 16:32:40 +02:00
Lennart Poettering
20240b071b sysctl-util: per coding style, compare chars explicit against 0. 2021-09-15 16:32:40 +02:00
Lennart Poettering
d1469b7095 sysctl-util: make sysctl_read_ip_property() a wrapper around sysctl_read()
let's do what we did for sysctl_write()/sysctl_write_ip_property() also
for the read paths: i.e. make one a wrapper of the other, and add more
careful input validation.
2021-09-15 16:32:40 +02:00
Lennart Poettering
f9755203b9 sysctl-util: modernize sysctl_read() a bit
Let's add similar path validation to sysctl_read() as we already have in
sysctl_write().

Let's also drop the trailing newline from the returned string, like
sysctl_read_ip_property() already does it.

(I checked all users of this, they don't care)
2021-09-15 16:32:40 +02:00
Lennart Poettering
6aebfec3a5 sysctl-util: make sysctl_write_ip_property() a wrapper around sysctl_write()
It does the same stuff, let's use the same codepaths as much as we can.

And while we are at it, let's generate good error codes in case we are
called with unsupported parameters/let's validate stuff more that might
originate from user input.
2021-09-15 16:32:40 +02:00
Jan Janssen
1b965abc66 sd-boot: Add support for changing console mode at runtime 2021-09-15 16:32:18 +02:00
Lennart Poettering
13239c86e0 sysctl-util: rework sysctl_write() to wrap write_string_file()
The sysctl_write_ip_property() call already uses write_string_file(), so
let's do so here, too, to make the codepaths more uniform.

While we are at it, let's also validate the passed path a bit, since we
shouldn't allow sysctls with /../ or such in the name. Hence simplify
the path first, and then check if it is normalized, and refuse if not.
2021-09-15 16:19:45 +02:00
Lennart Poettering
be991d7678 fileio: set O_NOCTTY when reading virtual files
Better be safe than sorry, maybe someone points this call to a TTY one
day, and we'd rather not make it our controlling TTY in that case.
2021-09-15 16:19:45 +02:00
Lennart Poettering
7ab7547a40 fileio: lower maximum virtual file buffer size by one byte
When reading virtual files (i.e. procfs, sysfs, …) we currently put a
limit of 4M-1 on that. We have to pick something, and we have to read
these files in a single read() (since the kernel generally doesn't
support continuation read()s for them). 4M-1 is actually the maximum
size the kernel allows for reads from files in /proc/sys/, all larger
reads will result in an ENOMEM error (which is really weird, but the
kernel does what the kernel does). Hence 4M-1 sounds like a smart
choice.

However, we made one mistake here: in order to be able to detect EOFs
properly we actually read one byte more than we actually intend to
return: if that extra byte can be read, then we know the file is
actually larger than our limit and we can generate an EFBIG error from
that. However, if it cannot be read then we know EOF was hit, and we are
good. So ultimately after all we issued a single 4M read, which the
kernel then responds with ENOMEM to.  And that means read_virtual_file()
actually doesn't work properly right now on /proc/sys/. Let's fix that.

The fix is simple, lower the limit of the the buffer we intend to return
by one, i.e. 4M-2. That way, the read() we'll issue is exactly as large
as the limit the kernel allows, and we still get safely detect EOF from
it.
2021-09-15 16:19:45 +02:00
Lennart Poettering
84b5e291e2 watchdog: add ", ignoring" to log messages about errors we ignore
As per coding style. Also downgrade relevant log messages to
LOG_WARNING.
2021-09-15 16:01:02 +02:00
Lennart Poettering
a4588af942 watchdog: pass right error code to log function so that %m works 2021-09-15 16:00:20 +02:00
Frantisek Sumsal
2ea7eb003c repart: mark an assert()-only variable as unused
otherwise compilation with -Db_ndebug=true complains about a
set-but-not-used variable:

```
 ../src/partition/repart.c:907:33: error: variable 'left' set but not used [-Werror,-Wunused-but-set-variable]
                 uint64_t start, left;
                                                 ^
                                                 1 error generated.
```
2021-09-15 15:46:19 +02:00
Frantisek Sumsal
d7ac09520b tree-wide: mark set-but-not-used variables as unused to make LLVM happy
LLVM 13 introduced `-Wunused-but-set-variable` diagnostic flag, which
trips over some intentionally set-but-not-used variables or variables
attached to cleanup handlers with side effects (`_cleanup_umask_`,
`_cleanup_(notify_on_cleanup)`, `_cleanup_(restore_sigsetp)`, etc.):

```
../src/basic/process-util.c:1257:46: error: variable 'saved_ssp' set but not used [-Werror,-Wunused-but-set-variable]
        _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL;
                                                     ^
                                                     1 error generated.
```
2021-09-15 13:09:45 +02:00
Jan Janssen
134144abc8 sd-boot: Simplify setting console mode 2021-09-15 10:48:19 +02:00
Frantisek Sumsal
bd8ea741a4 ci: build with clang-13
Also, drop clang-10 builds to conserve resources.
2021-09-14 19:06:01 +02:00
50 changed files with 471 additions and 295 deletions

View File

@ -20,9 +20,9 @@ jobs:
env:
- { COMPILER: "gcc", COMPILER_VERSION: "10" }
- { COMPILER: "gcc", COMPILER_VERSION: "11" }
- { COMPILER: "clang", COMPILER_VERSION: "10" }
- { COMPILER: "clang", COMPILER_VERSION: "11" }
- { COMPILER: "clang", COMPILER_VERSION: "12" }
- { COMPILER: "clang", COMPILER_VERSION: "13" }
env: ${{ matrix.env }}
steps:
- name: Repository checkout

View File

@ -151,6 +151,16 @@
<listitem><para>Decrease the timeout</para></listitem>
</varlistentry>
<varlistentry>
<term><keycap>r</keycap></term>
<listitem><para>Change screen resolution, skipping any unsupported modes.</para></listitem>
</varlistentry>
<varlistentry>
<term><keycap>R</keycap></term>
<listitem><para>Reset screen resolution to firmware or configuration file default.</para></listitem>
</varlistentry>
<varlistentry>
<term><keycap>p</keycap></term>
<listitem><para>Print status</para></listitem>

View File

@ -30,14 +30,16 @@
/* The maximum size of the file we'll read in one go in read_full_file() (64M). */
#define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U)
/* The maximum size of virtual files we'll read in one go in read_virtual_file() (4M). Note that this limit
* is different (and much lower) than the READ_FULL_BYTES_MAX limit. This reflects the fact that we use
* different strategies for reading virtual and regular files: virtual files are generally size constrained:
* there we allocate the full buffer size in advance. Regular files OTOH can be much larger, and here we grow
* the allocations exponentially in a loop. In glibc large allocations are immediately backed by mmap()
* making them relatively slow (measurably so). Thus, when allocating the full buffer in advance the large
* limit is a problem. When allocating piecemeal it's not. Hence pick two distinct limits. */
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 1U)
/* The maximum size of virtual files (i.e. procfs, sysfs, and other virtual "API" files) we'll read in one go
* in read_virtual_file(). Note that this limit is different (and much lower) than the READ_FULL_BYTES_MAX
* limit. This reflects the fact that we use different strategies for reading virtual and regular files:
* virtual files we generally have to read in a single read() syscall since the kernel doesn't support
* continuation read()s for them. Thankfully they are somewhat size constrained. Thus we can allocate the
* full potential buffer in advance. Regular files OTOH can be much larger, and there we grow the allocations
* exponentially in a loop. We use a size limit of 4M-2 because 4M-1 is the maximum buffer that /proc/sys/
* allows us to read() (larger reads will fail with ENOMEM), and we want to read one extra byte so that we
* can detect EOFs. */
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
int fopen_unlocked(const char *path, const char *options, FILE **ret) {
assert(ret);
@ -393,7 +395,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
* contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on
* partial success, 1 if untruncated contents were read. */
fd = open(filename, O_RDONLY|O_CLOEXEC);
fd = open(filename, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;

View File

@ -3,15 +3,15 @@
#include "nulstr-util.h"
#include "string-util.h"
bool nulstr_contains(const char *nulstr, const char *needle) {
const char* nulstr_get(const char *nulstr, const char *needle) {
const char *i;
if (!nulstr)
return false;
return NULL;
NULSTR_FOREACH(i, nulstr)
if (streq(i, needle))
return true;
return i;
return false;
return NULL;
}

View File

@ -10,4 +10,8 @@
#define NULSTR_FOREACH_PAIR(i, j, l) \
for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
bool nulstr_contains(const char *nulstr, const char *needle);
const char* nulstr_get(const char *nulstr, const char *needle);
static inline bool nulstr_contains(const char *nulstr, const char *needle) {
return nulstr_get(nulstr, needle);
}

View File

@ -1254,7 +1254,7 @@ int safe_fork_full(
pid_t original_pid, pid;
sigset_t saved_ss, ss;
_cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL;
_unused_ _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL;
bool block_signals = false, block_all = false;
int prio, r;

View File

@ -793,7 +793,7 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
/* Let's refuse "all" and "default" as interface name, to avoid collisions with the special sysctl
* directories /proc/sys/net/{ipv4,ipv6}/conf/{all,default} */
if (STR_IN_SET(p, "all", "default"))
if (!FLAGS_SET(flags, IFNAME_VALID_SPECIAL) && STR_IN_SET(p, "all", "default"))
return false;
for (const char *t = p; *t; t++) {

View File

@ -135,9 +135,10 @@ int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
typedef enum {
IFNAME_VALID_ALTERNATIVE = 1 << 0,
IFNAME_VALID_NUMERIC = 1 << 1,
_IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
IFNAME_VALID_ALTERNATIVE = 1 << 0, /* Allow "altnames" too */
IFNAME_VALID_NUMERIC = 1 << 1, /* Allow decimal formatted ifindexes too */
IFNAME_VALID_SPECIAL = 1 << 2, /* Allow the special names "all" and "default" */
_IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC | IFNAME_VALID_SPECIAL,
} IfnameValidFlags;
bool ifname_valid_char(char a);
bool ifname_valid_full(const char *p, IfnameValidFlags flags);

View File

@ -5,11 +5,13 @@
#include <stdio.h>
#include <unistd.h>
#include "af-list.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
#include "macro.h"
#include "path-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "sysctl-util.h"
@ -36,7 +38,7 @@ char *sysctl_normalize(char *s) {
path_simplify(s);
/* Kill the leading slash, but keep the first character of the string in the same place. */
if (*s == '/' && *(s+1))
if (s[0] == '/' && s[1] != 0)
memmove(s, s+1, strlen(s));
return s;
@ -44,25 +46,19 @@ char *sysctl_normalize(char *s) {
int sysctl_write(const char *property, const char *value) {
char *p;
_cleanup_close_ int fd = -1;
assert(property);
assert(value);
log_debug("Setting '%s' to '%.*s'.", property, (int) strcspn(value, NEWLINE), value);
p = strjoina("/proc/sys/", property);
fd = open(p, O_WRONLY|O_CLOEXEC);
if (fd < 0)
return -errno;
if (!endswith(value, "\n"))
value = strjoina(value, "\n");
path_simplify(p);
if (!path_is_normalized(p))
return -EINVAL;
if (write(fd, value, strlen(value)) < 0)
return -errno;
log_debug("Setting '%s' to '%s'", p, value);
return 0;
return write_string_file(p, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
}
int sysctl_writef(const char *property, const char *format, ...) {
@ -83,48 +79,59 @@ int sysctl_writef(const char *property, const char *format, ...) {
int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value) {
const char *p;
assert(IN_SET(af, AF_INET, AF_INET6));
assert(property);
assert(value);
p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6",
ifname ? "/conf/" : "", strempty(ifname),
property[0] == '/' ? "" : "/", property);
if (!IN_SET(af, AF_INET, AF_INET6))
return -EAFNOSUPPORT;
log_debug("Setting '%s' to '%s'", p, value);
if (ifname) {
if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL))
return -EINVAL;
return write_string_file(p, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property);
} else
p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property);
return sysctl_write(p, value);
}
int sysctl_read(const char *property, char **ret) {
char *p;
assert(property);
assert(ret);
p = strjoina("/proc/sys/", property);
return read_full_virtual_file(p, ret, NULL);
}
int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) {
_cleanup_free_ char *value = NULL;
const char *p;
int r;
assert(IN_SET(af, AF_INET, AF_INET6));
assert(property);
p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6",
ifname ? "/conf/" : "", strempty(ifname),
property[0] == '/' ? "" : "/", property);
p = strjoina("/proc/sys/", property);
r = read_full_virtual_file(p, &value, NULL);
path_simplify(p);
if (!path_is_normalized(p)) /* Filter out attempts to write to /proc/sys/../../…, just in case */
return -EINVAL;
r = read_full_virtual_file(p, ret, NULL);
if (r < 0)
return r;
truncate_nl(value);
if (ret)
*ret = TAKE_PTR(value);
delete_trailing_chars(*ret, NEWLINE);
return r;
}
int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) {
const char *p;
assert(property);
if (!IN_SET(af, AF_INET, AF_INET6))
return -EAFNOSUPPORT;
if (ifname) {
if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL))
return -EINVAL;
p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property);
} else
p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property);
return sysctl_read(p, ret);
}

View File

@ -286,7 +286,8 @@ int unit_file_build_name_map(
FOREACH_DIRENT(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
char *filename;
_cleanup_free_ char *_filename_free = NULL, *simplified = NULL;
_unused_ _cleanup_free_ char *_filename_free = NULL;
_cleanup_free_ char *simplified = NULL;
const char *suffix, *dst = NULL;
bool valid_unit_name;

View File

@ -69,8 +69,8 @@ typedef struct {
BOOLEAN auto_entries;
BOOLEAN auto_firmware;
BOOLEAN force_menu;
UINTN console_mode;
enum console_mode_change_type console_mode_change;
INT64 console_mode;
INT64 console_mode_efivar;
RandomSeedMode random_seed_mode;
} Config;
@ -370,13 +370,13 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
UINTN timeout;
BOOLEAN modevar;
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
UINTN x, y;
UINTN x_max, y_max;
assert(config);
assert(loaded_image_path);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, COLOR_NORMAL);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
clear_screen(COLOR_NORMAL);
console_query_mode(&x_max, &y_max);
Print(L"systemd-boot version: " GIT_VERSION "\n");
Print(L"architecture: " EFI_MACHINE_TYPE_NAME "\n");
@ -384,10 +384,8 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
Print(L"UEFI specification: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
Print(L"firmware vendor: %s\n", ST->FirmwareVendor);
Print(L"firmware version: %d.%02d\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
if (uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x, &y) == EFI_SUCCESS)
Print(L"console size: %d x %d\n", x, y);
Print(L"console mode: %d/%ld\n", ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - 1LL);
Print(L"console size: %d x %d\n", x_max, y_max);
Print(L"SecureBoot: %s\n", yes_no(secure_boot_enabled()));
if (efivar_get_boolean_u8(EFI_GLOBAL_GUID, L"SetupMode", &modevar) == EFI_SUCCESS)
@ -499,8 +497,6 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
Print(L"\n--- press key ---\n\n");
console_key_read(&key, 0);
}
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
}
static BOOLEAN menu_run(
@ -513,107 +509,115 @@ static BOOLEAN menu_run(
assert(loaded_image_path);
EFI_STATUS err;
UINTN visible_max;
UINTN visible_max = 0;
UINTN idx_highlight = config->idx_default;
UINTN idx_highlight_prev = 0;
UINTN idx_first;
UINTN idx_last;
BOOLEAN refresh = TRUE;
BOOLEAN highlight = FALSE;
UINTN line_width = 0;
UINTN entry_padding = 3;
CHAR16 **lines;
UINTN x_start;
UINTN y_start;
UINTN x_max;
UINTN y_max;
CHAR16 *status = NULL;
CHAR16 *clearline;
UINTN idx_first = 0, idx_last = 0;
BOOLEAN new_mode = TRUE, clear = TRUE;
BOOLEAN refresh = TRUE, highlight = FALSE;
UINTN x_start = 0, y_start = 0, y_status = 0;
UINTN x_max, y_max;
CHAR16 **lines = NULL, *status = NULL, *clearline = NULL;
UINTN timeout_remain = config->timeout_sec;
INT16 idx;
BOOLEAN exit = FALSE;
BOOLEAN run = TRUE;
BOOLEAN exit = FALSE, run = TRUE;
INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
graphics_mode(FALSE);
uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, COLOR_NORMAL);
/* draw a single character to make ClearScreen work on some firmware */
Print(L" ");
if (config->console_mode_change != CONSOLE_MODE_KEEP) {
err = console_set_mode(&config->console_mode, config->console_mode_change);
if (EFI_ERROR(err)) {
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
log_error_stall(L"Error switching console mode to %lu: %r", (UINT64)config->console_mode, err);
}
} else
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
config->console_mode_efivar : config->console_mode);
if (EFI_ERROR(err)) {
x_max = 80;
y_max = 25;
clear_screen(COLOR_NORMAL);
log_error_stall(L"Error switching console mode: %r", err);
}
visible_max = y_max - 2;
/* Drawing entries starts at idx_first until idx_last. We want to make
* sure that idx_highlight is centered, but not if we are close to the
* beginning/end of the entry list. Otherwise we would have a half-empty
* screen. */
if (config->entry_count <= visible_max || idx_highlight <= visible_max / 2)
idx_first = 0;
else if (idx_highlight >= config->entry_count - (visible_max / 2))
idx_first = config->entry_count - visible_max;
else
idx_first = idx_highlight - (visible_max / 2);
idx_last = idx_first + visible_max - 1;
/* length of the longest entry */
for (UINTN i = 0; i < config->entry_count; i++)
line_width = MAX(line_width, StrLen(config->entries[i]->title_show));
line_width = MIN(line_width + 2 * entry_padding, x_max);
/* offsets to center the entries on the screen */
x_start = (x_max - (line_width)) / 2;
if (config->entry_count < visible_max)
y_start = ((visible_max - config->entry_count) / 2) + 1;
else
y_start = 0;
/* menu entries title lines */
lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count);
for (UINTN i = 0; i < config->entry_count; i++) {
UINTN j;
lines[i] = AllocatePool(((line_width + 1) * sizeof(CHAR16)));
UINTN padding = (line_width - MIN(StrLen(config->entries[i]->title_show), line_width)) / 2;
for (j = 0; j < padding; j++)
lines[i][j] = ' ';
for (UINTN k = 0; config->entries[i]->title_show[k] != '\0' && j < line_width; j++, k++)
lines[i][j] = config->entries[i]->title_show[k];
for (; j < line_width; j++)
lines[i][j] = ' ';
lines[i][line_width] = '\0';
}
clearline = AllocatePool((x_max+1) * sizeof(CHAR16));
for (UINTN i = 0; i < x_max; i++)
clearline[i] = ' ';
clearline[x_max] = 0;
while (!exit) {
UINT64 key;
if (refresh) {
if (new_mode) {
UINTN line_width = 0, entry_padding = 3;
console_query_mode(&x_max, &y_max);
/* account for padding+status */
visible_max = y_max - 2;
/* Drawing entries starts at idx_first until idx_last. We want to make
* sure that idx_highlight is centered, but not if we are close to the
* beginning/end of the entry list. Otherwise we would have a half-empty
* screen. */
if (config->entry_count <= visible_max || idx_highlight <= visible_max / 2)
idx_first = 0;
else if (idx_highlight >= config->entry_count - (visible_max / 2))
idx_first = config->entry_count - visible_max;
else
idx_first = idx_highlight - (visible_max / 2);
idx_last = idx_first + visible_max - 1;
/* length of the longest entry */
for (UINTN i = 0; i < config->entry_count; i++)
line_width = MAX(line_width, StrLen(config->entries[i]->title_show));
line_width = MIN(line_width + 2 * entry_padding, x_max);
/* offsets to center the entries on the screen */
x_start = (x_max - (line_width)) / 2;
if (config->entry_count < visible_max)
y_start = ((visible_max - config->entry_count) / 2) + 1;
else
y_start = 0;
/* Put status line after the entry list, but give it some breathing room. */
y_status = MIN(y_start + MIN(visible_max, config->entry_count) + 4, y_max - 1);
if (lines) {
for (UINTN i = 0; i < config->entry_count; i++)
FreePool(lines[i]);
FreePool(lines);
FreePool(clearline);
}
/* menu entries title lines */
lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count);
for (UINTN i = 0; i < config->entry_count; i++) {
if (i < idx_first || i > idx_last)
continue;
UINTN j, padding;
lines[i] = AllocatePool(((line_width + 1) * sizeof(CHAR16)));
padding = (line_width - MIN(StrLen(config->entries[i]->title_show), line_width)) / 2;
for (j = 0; j < padding; j++)
lines[i][j] = ' ';
for (UINTN k = 0; config->entries[i]->title_show[k] != '\0' && j < line_width; j++, k++)
lines[i][j] = config->entries[i]->title_show[k];
for (; j < line_width; j++)
lines[i][j] = ' ';
lines[i][line_width] = '\0';
}
clearline = AllocatePool((x_max+1) * sizeof(CHAR16));
for (UINTN i = 0; i < x_max; i++)
clearline[i] = ' ';
clearline[x_max] = 0;
new_mode = FALSE;
clear = TRUE;
}
if (clear) {
clear_screen(COLOR_NORMAL);
clear = FALSE;
refresh = TRUE;
}
if (refresh) {
for (UINTN i = idx_first; i <= idx_last && i < config->entry_count; i++) {
print_at(x_start, y_start + i - idx_first,
(i == idx_highlight) ? COLOR_HIGHLIGHT : COLOR_ENTRY,
lines[i]);
@ -649,7 +653,7 @@ static BOOLEAN menu_run(
x = (x_max - len) / 2;
else
x = 0;
print_at(0, y_max - 1, COLOR_NORMAL, clearline + (x_max - x));
print_at(0, y_status, COLOR_NORMAL, clearline + (x_max - x));
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, status);
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len);
}
@ -671,7 +675,7 @@ static BOOLEAN menu_run(
if (status) {
FreePool(status);
status = NULL;
print_at(0, y_max - 1, COLOR_NORMAL, clearline + 1);
print_at(0, y_status, COLOR_NORMAL, clearline + 1);
}
idx_highlight_prev = idx_highlight;
@ -733,7 +737,7 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'H'):
case KEYPRESS(0, 0, '?'):
/* This must stay below 80 characters! Q/v/Ctrl+l deliberately not advertised. */
status = StrDuplicate(L"(d)efault (t/T)timeout (e)dit (p)rint (h)elp");
status = StrDuplicate(L"(d)efault (t/T)timeout (e)dit (r/R)resolution (p)rint (h)elp");
break;
case KEYPRESS(0, 0, 'Q'):
@ -813,9 +817,9 @@ static BOOLEAN menu_run(
* causing a scroll to happen that screws with our beautiful boot loader output.
* Since we cannot paint the last character of the edit line, we simply start
* at x-offset 1 for symmetry. */
print_at(1, y_max - 1, COLOR_EDIT, clearline + 2);
exit = line_edit(config->entries[idx_highlight]->options, &config->options_edit, x_max-2, y_max-1);
print_at(1, y_max - 1, COLOR_NORMAL, clearline + 2);
print_at(1, y_status, COLOR_EDIT, clearline + 2);
exit = line_edit(config->entries[idx_highlight]->options, &config->options_edit, x_max - 2, y_status);
print_at(1, y_status, COLOR_NORMAL, clearline + 2);
break;
case KEYPRESS(0, 0, 'v'):
@ -827,12 +831,35 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'p'):
case KEYPRESS(0, 0, 'P'):
print_status(config, loaded_image_path);
refresh = TRUE;
clear = TRUE;
break;
case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'):
case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('l')):
refresh = TRUE;
clear = TRUE;
break;
case KEYPRESS(0, 0, 'r'):
err = console_set_mode(CONSOLE_MODE_NEXT);
if (EFI_ERROR(err))
status = PoolPrint(L"Error changing console mode: %r", err);
else {
config->console_mode_efivar = ST->ConOut->Mode->Mode;
status = PoolPrint(L"Console mode changed to %ld.", config->console_mode_efivar);
}
new_mode = TRUE;
break;
case KEYPRESS(0, 0, 'R'):
config->console_mode_efivar = CONSOLE_MODE_KEEP;
err = console_set_mode(config->console_mode == CONSOLE_MODE_KEEP ?
console_mode_initial : config->console_mode);
if (EFI_ERROR(err))
status = PoolPrint(L"Error resetting console mode: %r", err);
else
status = PoolPrint(L"Console mode reset to %s default.",
config->console_mode == CONSOLE_MODE_KEEP ? L"firmware" : L"configuration file");
new_mode = TRUE;
break;
default:
@ -860,13 +887,23 @@ static BOOLEAN menu_run(
*chosen_entry = config->entries[idx_highlight];
/* The user is likely to cycle through several modes before
* deciding to keep one. Therefore, we update the EFI var after
* we left the menu to reduce nvram writes. */
if (console_mode_efivar_saved != config->console_mode_efivar) {
if (config->console_mode_efivar == CONSOLE_MODE_KEEP)
efivar_set(LOADER_GUID, L"LoaderConfigConsoleMode", NULL, EFI_VARIABLE_NON_VOLATILE);
else
efivar_set_uint_string(LOADER_GUID, L"LoaderConfigConsoleMode",
config->console_mode_efivar, EFI_VARIABLE_NON_VOLATILE);
}
for (UINTN i = 0; i < config->entry_count; i++)
FreePool(lines[i]);
FreePool(lines);
FreePool(clearline);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, COLOR_NORMAL);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
clear_screen(COLOR_NORMAL);
return run;
}
@ -1027,17 +1064,16 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
if (strcmpa((CHAR8 *)"console-mode", key) == 0) {
if (strcmpa((CHAR8 *)"auto", value) == 0)
config->console_mode_change = CONSOLE_MODE_AUTO;
config->console_mode = CONSOLE_MODE_AUTO;
else if (strcmpa((CHAR8 *)"max", value) == 0)
config->console_mode_change = CONSOLE_MODE_MAX;
config->console_mode = CONSOLE_MODE_FIRMWARE_MAX;
else if (strcmpa((CHAR8 *)"keep", value) == 0)
config->console_mode_change = CONSOLE_MODE_KEEP;
config->console_mode = CONSOLE_MODE_KEEP;
else {
_cleanup_freepool_ CHAR16 *s = NULL;
s = stra_to_str(value);
config->console_mode = Atoi(s);
config->console_mode_change = CONSOLE_MODE_SET;
config->console_mode = MIN(Atoi(s), (UINTN)CONSOLE_MODE_RANGE_MAX);
}
continue;
@ -1410,7 +1446,7 @@ static VOID config_entry_add_from_file(
static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
_cleanup_freepool_ CHAR8 *content = NULL;
UINTN sec;
UINTN value;
EFI_STATUS err;
assert(root_dir);
@ -1421,27 +1457,33 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
.auto_firmware = TRUE,
.random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN,
.idx_default_efivar = -1,
.console_mode = CONSOLE_MODE_KEEP,
.console_mode_efivar = CONSOLE_MODE_KEEP,
};
err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL);
if (!EFI_ERROR(err))
config_defaults_load_from_file(config, content);
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeout", &sec);
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeout", &value);
if (!EFI_ERROR(err)) {
config->timeout_sec_efivar = sec > INTN_MAX ? INTN_MAX : sec;
config->timeout_sec = sec;
config->timeout_sec_efivar = value > INTN_MAX ? INTN_MAX : value;
config->timeout_sec = value;
} else
config->timeout_sec_efivar = -1;
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeoutOneShot", &sec);
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeoutOneShot", &value);
if (!EFI_ERROR(err)) {
/* Unset variable now, after all it's "one shot". */
(void) efivar_set(LOADER_GUID, L"LoaderConfigTimeoutOneShot", NULL, EFI_VARIABLE_NON_VOLATILE);
config->timeout_sec = sec;
config->timeout_sec = value;
config->force_menu = TRUE; /* force the menu when this is set */
}
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigConsoleMode", &value);
if (!EFI_ERROR(err))
config->console_mode_efivar = value;
}
static VOID config_load_entries(

View File

@ -8,6 +8,9 @@
#define SYSTEM_FONT_WIDTH 8
#define SYSTEM_FONT_HEIGHT 19
#define HORIZONTAL_MAX_OK 1920
#define VERTICAL_MAX_OK 1080
#define VIEWPORT_RATIO 10
#define EFI_SIMPLE_TEXT_INPUT_EX_GUID \
&(const EFI_GUID) EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID
@ -115,51 +118,36 @@ EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec) {
return EFI_SUCCESS;
}
static EFI_STATUS change_mode(UINTN mode) {
static EFI_STATUS change_mode(INT64 mode) {
EFI_STATUS err;
INT32 old_mode;
/* SetMode expects a UINTN, so make sure these values are sane. */
mode = CLAMP(mode, CONSOLE_MODE_RANGE_MIN, CONSOLE_MODE_RANGE_MAX);
old_mode = MAX(CONSOLE_MODE_RANGE_MIN, ST->ConOut->Mode->Mode);
err = uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, mode);
if (!EFI_ERROR(err))
return EFI_SUCCESS;
/* Special case mode 1: when using OVMF and qemu, setting it returns error
* and breaks console output. */
if (EFI_ERROR(err) && mode == 1)
uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, (UINTN)0);
/* Something went wrong. Output is probably borked, so try to revert to previous mode. */
if (!EFI_ERROR(uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, old_mode)))
return err;
/* Maybe the device is on fire? */
uefi_call_wrapper(ST->ConOut->Reset, 2, ST->ConOut, TRUE);
uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, CONSOLE_MODE_RANGE_MIN);
return err;
}
static UINT64 text_area_from_font_size(void) {
EFI_STATUS err;
UINT64 text_area;
UINTN rows, columns;
err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &columns, &rows);
if (EFI_ERROR(err)) {
columns = 80;
rows = 25;
}
text_area = SYSTEM_FONT_WIDTH * SYSTEM_FONT_HEIGHT * (UINT64)rows * (UINT64)columns;
return text_area;
}
static EFI_STATUS mode_auto(UINTN *mode) {
const UINT32 HORIZONTAL_MAX_OK = 1920;
const UINT32 VERTICAL_MAX_OK = 1080;
const UINT64 VIEWPORT_RATIO = 10;
UINT64 screen_area, text_area;
static const EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static INT64 get_auto_mode(void) {
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
EFI_STATUS err;
BOOLEAN keep = FALSE;
assert(mode);
err = LibLocateProtocol((EFI_GUID*) &GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
err = LibLocateProtocol(&GraphicsOutputProtocol, (VOID **)&GraphicsOutput);
if (!EFI_ERROR(err) && GraphicsOutput->Mode && GraphicsOutput->Mode->Info) {
Info = GraphicsOutput->Mode->Info;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = GraphicsOutput->Mode->Info;
BOOLEAN keep = FALSE;
/* Start verifying if we are in a resolution larger than Full HD
* (1920x1080). If we're not, assume we're in a good mode and do not
@ -170,19 +158,19 @@ static EFI_STATUS mode_auto(UINTN *mode) {
* area to the text viewport area. If it's less than 10 times bigger,
* then assume the text is readable and keep the text mode. */
else {
screen_area = (UINT64)Info->HorizontalResolution * (UINT64)Info->VerticalResolution;
text_area = text_area_from_font_size();
UINT64 text_area;
UINTN x_max, y_max;
UINT64 screen_area = (UINT64)Info->HorizontalResolution * (UINT64)Info->VerticalResolution;
console_query_mode(&x_max, &y_max);
text_area = SYSTEM_FONT_WIDTH * SYSTEM_FONT_HEIGHT * (UINT64)x_max * (UINT64)y_max;
if (text_area != 0 && screen_area/text_area < VIEWPORT_RATIO)
keep = TRUE;
}
}
if (keep) {
/* Just clear the screen instead of changing the mode and return. */
*mode = ST->ConOut->Mode->Mode;
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
return EFI_SUCCESS;
if (keep)
return ST->ConOut->Mode->Mode;
}
/* If we reached here, then we have a high resolution screen and the text
@ -191,32 +179,72 @@ static EFI_STATUS mode_auto(UINTN *mode) {
* standard mode, which is provided by the device manufacturer, so it should
* be a good mode.
* Note: MaxMode is the number of modes, not the last mode. */
if (ST->ConOut->Mode->MaxMode > 2)
*mode = 2;
if (ST->ConOut->Mode->MaxMode > CONSOLE_MODE_FIRMWARE_FIRST)
return CONSOLE_MODE_FIRMWARE_FIRST;
/* Try again with mode different than zero (assume user requests
* auto mode due to some problem with mode zero). */
else if (ST->ConOut->Mode->MaxMode == 2)
*mode = 1;
/* Else force mode change to zero. */
else
*mode = 0;
if (ST->ConOut->Mode->MaxMode > CONSOLE_MODE_80_50)
return CONSOLE_MODE_80_50;
return change_mode(*mode);
return CONSOLE_MODE_80_25;
}
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how) {
assert(mode);
EFI_STATUS console_set_mode(INT64 mode) {
switch (mode) {
case CONSOLE_MODE_KEEP:
/* If the firmware indicates the current mode is invalid, change it anyway. */
if (ST->ConOut->Mode->Mode < CONSOLE_MODE_RANGE_MIN)
return change_mode(CONSOLE_MODE_RANGE_MIN);
return EFI_SUCCESS;
if (how == CONSOLE_MODE_AUTO)
return mode_auto(mode);
case CONSOLE_MODE_NEXT:
if (ST->ConOut->Mode->MaxMode <= CONSOLE_MODE_RANGE_MIN)
return EFI_UNSUPPORTED;
if (how == CONSOLE_MODE_MAX) {
mode = MAX(CONSOLE_MODE_RANGE_MIN, ST->ConOut->Mode->Mode);
do {
mode = (mode + 1) % ST->ConOut->Mode->MaxMode;
if (!EFI_ERROR(change_mode(mode)))
break;
/* If this mode is broken/unsupported, try the next.
* If mode is 0, we wrapped around and should stop. */
} while (mode > CONSOLE_MODE_RANGE_MIN);
return EFI_SUCCESS;
case CONSOLE_MODE_AUTO:
return change_mode(get_auto_mode());
case CONSOLE_MODE_FIRMWARE_MAX:
/* Note: MaxMode is the number of modes, not the last mode. */
if (ST->ConOut->Mode->MaxMode > 0)
*mode = ST->ConOut->Mode->MaxMode-1;
else
*mode = 0;
return change_mode(ST->ConOut->Mode->MaxMode - 1LL);
default:
return change_mode(mode);
}
}
EFI_STATUS console_query_mode(UINTN *x_max, UINTN *y_max) {
EFI_STATUS err;
assert(x_max);
assert(y_max);
err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, x_max, y_max);
if (EFI_ERROR(err)) {
/* Fallback values mandated by UEFI spec. */
switch (ST->ConOut->Mode->Mode) {
case CONSOLE_MODE_80_50:
*x_max = 80;
*y_max = 50;
break;
case CONSOLE_MODE_80_25:
default:
*x_max = 80;
*y_max = 25;
}
}
return change_mode(*mode);
return err;
}

View File

@ -9,12 +9,23 @@
#define KEYCHAR(k) ((k) & 0xffff)
#define CHAR_CTRL(c) ((c) - 'a' + 1)
enum console_mode_change_type {
CONSOLE_MODE_KEEP = 0,
CONSOLE_MODE_SET,
enum {
/* Console mode is a INT32 in EFI. We use INT64 to make room for our special values. */
CONSOLE_MODE_RANGE_MIN = 0,
CONSOLE_MODE_RANGE_MAX = INT32_MAX, /* This is just the theoretical limit. */
CONSOLE_MODE_INVALID = -1, /* UEFI uses -1 if the device is not in a valid text mode. */
CONSOLE_MODE_80_25 = 0, /* 80x25 is required by UEFI spec. */
CONSOLE_MODE_80_50 = 1, /* 80x50 may be supported. */
CONSOLE_MODE_FIRMWARE_FIRST = 2, /* First custom mode, if supported. */
/* These are our own mode values that map to concrete values at runtime. */
CONSOLE_MODE_KEEP = CONSOLE_MODE_RANGE_MAX + 1LL,
CONSOLE_MODE_NEXT,
CONSOLE_MODE_AUTO,
CONSOLE_MODE_MAX,
CONSOLE_MODE_FIRMWARE_MAX, /* 'max' in config. */
};
EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec);
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how);
EFI_STATUS console_set_mode(INT64 mode);
EFI_STATUS console_query_mode(UINTN *x_max, UINTN *y_max);

View File

@ -522,3 +522,8 @@ VOID print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str) {
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, attr);
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)str);
}
VOID clear_screen(UINTN attr) {
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, attr);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
}

View File

@ -93,3 +93,4 @@ static inline VOID *mempmem_safe(const VOID *haystack, UINTN haystack_len, const
}
VOID print_at(UINTN x, UINTN y, UINTN attr, const CHAR16 *str);
VOID clear_screen(UINTN attr);

View File

@ -1758,7 +1758,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
{
/* This block is (optionally) done with the reloading counter bumped */
_cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
_unused_ _cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
/* If we will deserialize make sure that during enumeration this is already known, so we increase the
* counter here already */
@ -3237,7 +3237,7 @@ int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
}
int manager_reload(Manager *m) {
_cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
_unused_ _cleanup_(manager_reloading_stopp) Manager *reloading = NULL;
_cleanup_fdset_free_ FDSet *fds = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;

View File

@ -853,7 +853,7 @@ static int mount_private_dev(MountEntry *m) {
char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
bool can_mknod = true;
_cleanup_umask_ mode_t u;
_unused_ _cleanup_umask_ mode_t u;
int r;
assert(m);

View File

@ -1674,7 +1674,7 @@ static int run(int argc, char *argv[]) {
verb = argv[1];
if (streq(verb, "attach")) {
_cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
_unused_ _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
_cleanup_(erase_and_freep) void *key_data = NULL;
const char *volume, *source, *key_file, *options;
crypt_status_info status;

View File

@ -14,7 +14,7 @@
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
int r;
log_setup();

View File

@ -166,10 +166,10 @@ static void context_read_os_release(Context *c) {
c->etc_os_release_stat = current_stat;
}
static bool valid_chassis(const char *chassis) {
static const char* valid_chassis(const char *chassis) {
assert(chassis);
return nulstr_contains(
return nulstr_get(
"vm\0"
"container\0"
"desktop\0"
@ -190,6 +190,7 @@ static bool valid_deployment(const char *deployment) {
}
static const char* fallback_chassis(void) {
const char *chassis;
char *type;
unsigned t;
int v, r;
@ -261,14 +262,14 @@ try_acpi:
r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
if (r < 0) {
log_debug_errno(r, "Failed read ACPI PM profile, ignoring: %m");
return NULL;
goto try_devicetree;
}
r = safe_atou(type, &t);
free(type);
if (r < 0) {
log_debug_errno(r, "Failed parse ACPI PM profile, ignoring: %m");
return NULL;
goto try_devicetree;
}
/* We only list the really obvious cases here as the ACPI data is not really super reliable.
@ -300,7 +301,24 @@ try_acpi:
log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t);
}
return NULL;
try_devicetree:
r = read_one_line_file("/sys/firmware/devicetree/base/chassis-type", &type);
if (r < 0) {
log_debug_errno(r, "Failed to read device-tree chassis type, ignoring: %m");
return NULL;
}
/* Note that the Devicetree specification uses the very same vocabulary
* of chassis types as we do, hence we do not need to translate these types:
*
* https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter3-devicenodes.rst */
chassis = valid_chassis(type);
if (!chassis)
log_debug("Invalid device-tree chassis type '%s', ignoring.", type);
free(type);
return chassis;
}
static char* context_fallback_icon_name(Context *c) {

View File

@ -311,7 +311,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
static int run(int argc, char *argv[]) {
_cleanup_(server_done) Server server = { .epoll_fd = -1 };
_cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
int r, n;
if (argc > 1)

View File

@ -1099,7 +1099,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
static int run(int argc, char **argv) {
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_cleanup_(erase_and_freep) char *key = NULL;
_cleanup_free_ char *cert = NULL, *trust = NULL;
int r;

View File

@ -272,7 +272,7 @@ int journal_remote_add_source(RemoteServer *s, int fd, char* name, bool own_name
int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
int r;
_cleanup_close_ int fd_ = fd;
_unused_ _cleanup_close_ int fd_ = fd;
char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
assert(fd >= 0);

View File

@ -820,7 +820,7 @@ static int open_journal(sd_journal **j) {
static int run(int argc, char **argv) {
_cleanup_(destroy_uploader) Uploader u = {};
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
bool use_journal;
int r;

View File

@ -903,7 +903,7 @@ static void dispatch_message_real(
pid_t object_pid) {
char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
_cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL;
_unused_ _cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL;
uid_t journal_uid;
ClientContext *o;

View File

@ -94,7 +94,8 @@ int device_add_property_aux(sd_device *device, const char *key, const char *valu
properties = &device->properties;
if (value) {
_cleanup_free_ char *new_key = NULL, *new_value = NULL, *old_key = NULL, *old_value = NULL;
_unused_ _cleanup_free_ char *old_value = NULL;
_cleanup_free_ char *new_key = NULL, *new_value = NULL, *old_key = NULL;
int r;
r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops_free_free);
@ -119,7 +120,8 @@ int device_add_property_aux(sd_device *device, const char *key, const char *valu
TAKE_PTR(new_key);
TAKE_PTR(new_value);
} else {
_cleanup_free_ char *old_key = NULL, *old_value = NULL;
_unused_ _cleanup_free_ char *old_value = NULL;
_cleanup_free_ char *old_key = NULL;
old_value = ordered_hashmap_remove2(*properties, key, (void**) &old_key);
}
@ -1939,7 +1941,8 @@ _public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
}
static int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
_cleanup_free_ char *new_key = NULL, *old_value = NULL;
_unused_ _cleanup_free_ char *old_value = NULL;
_cleanup_free_ char *new_key = NULL;
int r;
assert(device);

View File

@ -53,7 +53,7 @@ static void test_catalog_import_invalid(void) {
}
static void test_catalog_import_badid(void) {
_cleanup_ordered_hashmap_free_free_free_ OrderedHashmap *h = NULL;
_unused_ _cleanup_ordered_hashmap_free_free_free_ OrderedHashmap *h = NULL;
const char *input =
"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededede\n" \
"Subject: message\n" \

View File

@ -703,7 +703,7 @@ bool manager_all_buttons_ignored(Manager *m) {
int manager_read_utmp(Manager *m) {
#if ENABLE_UTMP
int r;
_cleanup_(utxent_cleanup) bool utmpx = false;
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
assert(m);

View File

@ -1323,7 +1323,7 @@ bool session_is_controller(Session *s, const char *sender) {
}
static void session_release_controller(Session *s, bool notify) {
_cleanup_free_ char *name = NULL;
_unused_ _cleanup_free_ char *name = NULL;
SessionDevice *sd;
if (!s->controller)

View File

@ -1157,7 +1157,7 @@ static int manager_run(Manager *m) {
static int run(int argc, char *argv[]) {
_cleanup_(manager_unrefp) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
int r;
log_set_facility(LOG_AUTH);

View File

@ -702,8 +702,10 @@ int config_parse_dhcp_send_option(
void *data,
void *userdata) {
_cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL;
_cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL;
_cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL;
_cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL;
_unused_ _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *old4 = NULL;
_unused_ _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *old6 = NULL;
uint32_t uint32_data, enterprise_identifier = 0;
_cleanup_free_ char *word = NULL, *q = NULL;
OrderedHashmap **options = data;

View File

@ -19,7 +19,7 @@
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
int r;
log_setup();

View File

@ -195,7 +195,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
int r;
log_setup();

View File

@ -2196,7 +2196,7 @@ static int copy_devnodes(const char *dest) {
"tty\0"
"net/tun\0";
_cleanup_umask_ mode_t u;
_unused_ _cleanup_umask_ mode_t u;
const char *d;
int r = 0;
@ -2279,7 +2279,7 @@ static int copy_devnodes(const char *dest) {
}
static int make_extra_nodes(const char *dest) {
_cleanup_umask_ mode_t u;
_unused_ _cleanup_umask_ mode_t u;
size_t i;
int r;
@ -2480,7 +2480,7 @@ static int setup_kmsg(int kmsg_socket) {
_cleanup_(unlink_and_freep) char *from = NULL;
_cleanup_free_ char *fifo = NULL;
_cleanup_close_ int fd = -1;
_cleanup_umask_ mode_t u;
_unused_ _cleanup_umask_ mode_t u;
int r;
assert(kmsg_socket >= 0);

View File

@ -303,7 +303,7 @@ enum nss_status userdb_getgrnam(
}
if (!g) {
_cleanup_(_nss_systemd_unblockp) bool blocked = false;
_unused_ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
if (strv_isempty(members))
return NSS_STATUS_NOTFOUND;
@ -365,7 +365,7 @@ enum nss_status userdb_getgrgid(
}
if (!g) {
_cleanup_(_nss_systemd_unblockp) bool blocked = false;
_unused_ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
/* So, quite possibly we have to extend an existing group record with additional members. But
* to do this we need to know the group name first. The group didn't exist via non-NSS

View File

@ -387,7 +387,7 @@ static void clear_candidate_hashmapp(Manager **m) {
static int monitor_memory_pressure_contexts_handler(sd_event_source *s, uint64_t usec, void *userdata) {
/* Don't want to use stale candidate data. Setting this will clear the candidate hashmap on return unless we
* update the candidate data (in which case clear_candidates will be NULL). */
_cleanup_(clear_candidate_hashmapp) Manager *clear_candidates = userdata;
_unused_ _cleanup_(clear_candidate_hashmapp) Manager *clear_candidates = userdata;
_cleanup_set_free_ Set *targets = NULL;
bool in_post_action_delay = false;
Manager *m = userdata;

View File

@ -116,7 +116,7 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char *argv[]) {
_cleanup_(notify_on_cleanup) const char *notify_msg = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_msg = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_free_ char *swap = NULL;
unsigned long long s = 0;

View File

@ -904,7 +904,8 @@ static void context_place_partitions(Context *context) {
for (size_t i = 0; i < context->n_free_areas; i++) {
FreeArea *a = context->free_areas[i];
uint64_t start, left;
_unused_ uint64_t left;
uint64_t start;
if (a->after) {
assert(a->after->offset != UINT64_MAX);

View File

@ -274,7 +274,7 @@ static int dns_cache_link_item(DnsCache *c, DnsCacheItem *i) {
first = hashmap_get(c->by_key, i->key);
if (first) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
_unused_ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
/* Keep a reference to the original key, while we manipulate the list. */
k = dns_resource_key_ref(first->key);

View File

@ -165,7 +165,7 @@ static int dns_query_candidate_add_transaction(
}
static int dns_query_candidate_go(DnsQueryCandidate *c) {
_cleanup_(dns_query_candidate_unrefp) DnsQueryCandidate *keep_c = NULL;
_unused_ _cleanup_(dns_query_candidate_unrefp) DnsQueryCandidate *keep_c = NULL;
DnsTransaction *t;
int r;
unsigned n = 0;

View File

@ -23,7 +23,7 @@
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
int r;
log_setup();

View File

@ -90,7 +90,7 @@
* Returns: 0 on success, negative error code on failure.
*/
int barrier_create(Barrier *b) {
_cleanup_(barrier_destroyp) Barrier *staging = b;
_unused_ _cleanup_(barrier_destroyp) Barrier *staging = b;
int r;
assert(b);

View File

@ -81,7 +81,7 @@ int make_inaccessible_nodes(
{ "inaccessible/blk", S_IFBLK | 0000 },
};
_cleanup_umask_ mode_t u;
_unused_ _cleanup_umask_ mode_t u;
int r;
if (!parent_dir)

View File

@ -25,7 +25,7 @@
#include "utmp-wtmp.h"
int utmp_get_runlevel(int *runlevel, int *previous) {
_cleanup_(utxent_cleanup) bool utmpx = false;
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
struct utmpx *found, lookup = { .ut_type = RUN_LVL };
const char *e;
@ -87,7 +87,7 @@ static void init_entry(struct utmpx *store, usec_t t) {
}
static int write_entry_utmp(const struct utmpx *store) {
_cleanup_(utxent_cleanup) bool utmpx = false;
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
assert(store);
@ -215,7 +215,7 @@ int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line
}
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
_cleanup_(utxent_cleanup) bool utmpx = false;
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
struct utmpx lookup = {
.ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
}, store, store_wtmp, *found;
@ -340,7 +340,7 @@ int utmp_wall(
bool (*match_tty)(const char *tty, void *userdata),
void *userdata) {
_cleanup_(utxent_cleanup) bool utmpx = false;
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
_cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
struct utmpx *u;
int r;

View File

@ -30,7 +30,7 @@ static int update_timeout(void) {
flags = WDIOS_DISABLECARD;
if (ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags) < 0)
return log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
return log_warning_errno(errno, "Failed to disable hardware watchdog, ignoring: %m");
} else {
int sec, flags;
usec_t t;
@ -38,7 +38,7 @@ static int update_timeout(void) {
t = DIV_ROUND_UP(watchdog_timeout, USEC_PER_SEC);
sec = MIN(t, (usec_t) INT_MAX); /* Saturate */
if (ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec) < 0)
return log_warning_errno(errno, "Failed to set timeout to %is: %m", sec);
return log_warning_errno(errno, "Failed to set timeout to %is, ignoring: %m", sec);
/* Just in case the driver is buggy */
assert(sec > 0);
@ -50,14 +50,14 @@ static int update_timeout(void) {
flags = WDIOS_ENABLECARD;
if (ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags) < 0) {
/* ENOTTY means the watchdog is always enabled so we're fine */
log_full(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING,
"Failed to enable hardware watchdog: %m");
log_full_errno(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING, errno,
"Failed to enable hardware watchdog, ignoring: %m");
if (!ERRNO_IS_NOT_SUPPORTED(errno))
return -errno;
}
if (ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0) < 0)
return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
return log_warning_errno(errno, "Failed to ping hardware watchdog, ignoring: %m");
watchdog_last_ping = now(clock_boottime_or_monotonic());
}
@ -75,10 +75,10 @@ static int open_watchdog(void) {
fn = watchdog_device ?: "/dev/watchdog";
watchdog_fd = open(fn, O_WRONLY|O_CLOEXEC);
if (watchdog_fd < 0)
return log_debug_errno(errno, "Failed to open watchdog device %s: %m", fn);
return log_debug_errno(errno, "Failed to open watchdog device %s, ignoring: %m", fn);
if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) < 0)
log_debug_errno(errno, "Hardware watchdog %s does not support WDIOC_GETSUPPORT ioctl: %m", fn);
log_debug_errno(errno, "Hardware watchdog %s does not support WDIOC_GETSUPPORT ioctl, ignoring: %m", fn);
else
log_info("Using hardware watchdog '%s', version %x, device %s",
ident.identity,
@ -156,7 +156,7 @@ int watchdog_ping(void) {
}
if (ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0) < 0)
return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
return log_warning_errno(errno, "Failed to ping hardware watchdog, ignoring: %m");
watchdog_last_ping = ntime;
return 0;
@ -172,7 +172,7 @@ void watchdog_close(bool disarm) {
/* Explicitly disarm it */
flags = WDIOS_DISABLECARD;
if (ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags) < 0)
log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
log_warning_errno(errno, "Failed to disable hardware watchdog, ignoring: %m");
/* To be sure, use magic close logic, too */
for (;;) {
@ -182,7 +182,7 @@ void watchdog_close(bool disarm) {
break;
if (errno != EINTR) {
log_error_errno(errno, "Failed to disarm watchdog timer: %m");
log_warning_errno(errno, "Failed to disarm watchdog timer, ignoring: %m");
break;
}
}

View File

@ -1,10 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-id128.h"
#include "errno-util.h"
#include "hostname-util.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tests.h"
static const char* cases[] = {
static const char* const cases[] = {
"a.b.c", "a/b/c",
"a/b/c", "a/b/c",
"a/b.c/d", "a/b.c/d",
@ -24,7 +28,7 @@ static void test_sysctl_normalize(void) {
log_info("/* %s */", __func__);
const char **s, **expected;
STRV_FOREACH_PAIR(s, expected, cases) {
STRV_FOREACH_PAIR(s, expected, (const char**) cases) {
_cleanup_free_ char *t;
assert_se(t = strdup(*s));
@ -35,10 +39,44 @@ static void test_sysctl_normalize(void) {
}
}
static void test_sysctl_read(void) {
_cleanup_free_ char *s = NULL, *h = NULL;
sd_id128_t a, b;
int r;
assert_se(sysctl_read("kernel/random/boot_id", &s) >= 0);
assert_se(sd_id128_from_string(s, &a) >= 0);
assert_se(sd_id128_get_boot(&b) >= 0);
assert_se(sd_id128_equal(a, b));
s = mfree(s);
assert_se(sysctl_read_ip_property(AF_INET, "lo", "forwarding", &s));
assert_se(STR_IN_SET(s, "0", "1"));
r = sysctl_write_ip_property(AF_INET, "lo", "forwarding", s);
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
s = mfree(s);
assert_se(sysctl_read_ip_property(AF_INET, NULL, "ip_forward", &s));
assert_se(STR_IN_SET(s, "0", "1"));
r = sysctl_write_ip_property(AF_INET, NULL, "ip_forward", s);
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
s = mfree(s);
assert_se(sysctl_read("kernel/hostname", &s) >= 0);
assert_se(gethostname_full(GET_HOSTNAME_ALLOW_NONE|GET_HOSTNAME_ALLOW_LOCALHOST, &h) >= 0);
assert_se(streq(s, h));
r = sysctl_write("kernel/hostname", s);
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO);
test_sysctl_normalize();
test_sysctl_read();
return 0;
}

View File

@ -87,7 +87,7 @@ settime:
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
const char *user = "systemd-timesync";
uid_t uid, uid_current;
gid_t gid;

View File

@ -338,7 +338,8 @@ static int process_and_watch_password_files(bool watch) {
_FD_MAX
};
_cleanup_close_ int notify = -1, signal_fd = -1, tty_block_fd = -1;
_unused_ _cleanup_close_ int tty_block_fd = -1;
_cleanup_close_ int notify = -1, signal_fd = -1;
struct pollfd pollfd[_FD_MAX];
sigset_t mask;
int r;

View File

@ -1136,7 +1136,8 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
manager_reload(manager);
break;
case UDEV_CTRL_SET_ENV: {
_cleanup_free_ char *key = NULL, *val = NULL, *old_key = NULL, *old_val = NULL;
_unused_ _cleanup_free_ char *old_val = NULL;
_cleanup_free_ char *key = NULL, *val = NULL, *old_key = NULL;
const char *eq;
eq = strchr(value->buf, '=');

View File

@ -24,7 +24,7 @@
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
int r;
log_setup();