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: env:
- { COMPILER: "gcc", COMPILER_VERSION: "10" } - { COMPILER: "gcc", COMPILER_VERSION: "10" }
- { COMPILER: "gcc", COMPILER_VERSION: "11" } - { COMPILER: "gcc", COMPILER_VERSION: "11" }
- { COMPILER: "clang", COMPILER_VERSION: "10" }
- { COMPILER: "clang", COMPILER_VERSION: "11" } - { COMPILER: "clang", COMPILER_VERSION: "11" }
- { COMPILER: "clang", COMPILER_VERSION: "12" } - { COMPILER: "clang", COMPILER_VERSION: "12" }
- { COMPILER: "clang", COMPILER_VERSION: "13" }
env: ${{ matrix.env }} env: ${{ matrix.env }}
steps: steps:
- name: Repository checkout - name: Repository checkout

View File

@ -151,6 +151,16 @@
<listitem><para>Decrease the timeout</para></listitem> <listitem><para>Decrease the timeout</para></listitem>
</varlistentry> </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> <varlistentry>
<term><keycap>p</keycap></term> <term><keycap>p</keycap></term>
<listitem><para>Print status</para></listitem> <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). */ /* 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) #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 /* The maximum size of virtual files (i.e. procfs, sysfs, and other virtual "API" files) we'll read in one go
* is different (and much lower) than the READ_FULL_BYTES_MAX limit. This reflects the fact that we use * in read_virtual_file(). Note that this limit is different (and much lower) than the READ_FULL_BYTES_MAX
* different strategies for reading virtual and regular files: virtual files are generally size constrained: * limit. This reflects the fact that we use different strategies for reading virtual and regular files:
* there we allocate the full buffer size in advance. Regular files OTOH can be much larger, and here we grow * virtual files we generally have to read in a single read() syscall since the kernel doesn't support
* the allocations exponentially in a loop. In glibc large allocations are immediately backed by mmap() * continuation read()s for them. Thankfully they are somewhat size constrained. Thus we can allocate the
* making them relatively slow (measurably so). Thus, when allocating the full buffer in advance the large * full potential buffer in advance. Regular files OTOH can be much larger, and there we grow the allocations
* limit is a problem. When allocating piecemeal it's not. Hence pick two distinct limits. */ * exponentially in a loop. We use a size limit of 4M-2 because 4M-1 is the maximum buffer that /proc/sys/
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 1U) * 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) { int fopen_unlocked(const char *path, const char *options, FILE **ret) {
assert(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 * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on
* partial success, 1 if untruncated contents were read. */ * 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) if (fd < 0)
return -errno; return -errno;

View File

@ -3,15 +3,15 @@
#include "nulstr-util.h" #include "nulstr-util.h"
#include "string-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; const char *i;
if (!nulstr) if (!nulstr)
return false; return NULL;
NULSTR_FOREACH(i, nulstr) NULSTR_FOREACH(i, nulstr)
if (streq(i, needle)) 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) \ #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)) 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; pid_t original_pid, pid;
sigset_t saved_ss, ss; 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; bool block_signals = false, block_all = false;
int prio, r; 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 /* 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} */ * 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; return false;
for (const char *t = p; *t; t++) { 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); int ip_tos_from_string(const char *s);
typedef enum { typedef enum {
IFNAME_VALID_ALTERNATIVE = 1 << 0, IFNAME_VALID_ALTERNATIVE = 1 << 0, /* Allow "altnames" too */
IFNAME_VALID_NUMERIC = 1 << 1, IFNAME_VALID_NUMERIC = 1 << 1, /* Allow decimal formatted ifindexes too */
_IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC, 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; } IfnameValidFlags;
bool ifname_valid_char(char a); bool ifname_valid_char(char a);
bool ifname_valid_full(const char *p, IfnameValidFlags flags); bool ifname_valid_full(const char *p, IfnameValidFlags flags);

View File

@ -5,11 +5,13 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "af-list.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "path-util.h" #include "path-util.h"
#include "socket-util.h"
#include "string-util.h" #include "string-util.h"
#include "sysctl-util.h" #include "sysctl-util.h"
@ -36,7 +38,7 @@ char *sysctl_normalize(char *s) {
path_simplify(s); path_simplify(s);
/* Kill the leading slash, but keep the first character of the string in the same place. */ /* 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)); memmove(s, s+1, strlen(s));
return s; return s;
@ -44,25 +46,19 @@ char *sysctl_normalize(char *s) {
int sysctl_write(const char *property, const char *value) { int sysctl_write(const char *property, const char *value) {
char *p; char *p;
_cleanup_close_ int fd = -1;
assert(property); assert(property);
assert(value); assert(value);
log_debug("Setting '%s' to '%.*s'.", property, (int) strcspn(value, NEWLINE), value);
p = strjoina("/proc/sys/", property); p = strjoina("/proc/sys/", property);
fd = open(p, O_WRONLY|O_CLOEXEC);
if (fd < 0)
return -errno;
if (!endswith(value, "\n")) path_simplify(p);
value = strjoina(value, "\n"); if (!path_is_normalized(p))
return -EINVAL;
if (write(fd, value, strlen(value)) < 0) log_debug("Setting '%s' to '%s'", p, value);
return -errno;
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, ...) { 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) { int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value) {
const char *p; const char *p;
assert(IN_SET(af, AF_INET, AF_INET6));
assert(property); assert(property);
assert(value); assert(value);
p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6", if (!IN_SET(af, AF_INET, AF_INET6))
ifname ? "/conf/" : "", strempty(ifname), return -EAFNOSUPPORT;
property[0] == '/' ? "" : "/", property);
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) { int sysctl_read(const char *property, char **ret) {
char *p; char *p;
int r;
assert(property); assert(property);
assert(ret);
p = strjoina("/proc/sys/", property); p = strjoina("/proc/sys/", property);
return read_full_virtual_file(p, ret, 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;
if (ret)
delete_trailing_chars(*ret, NEWLINE);
return r;
} }
int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) { int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) {
_cleanup_free_ char *value = NULL;
const char *p; const char *p;
int r;
assert(IN_SET(af, AF_INET, AF_INET6));
assert(property); assert(property);
p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6", if (!IN_SET(af, AF_INET, AF_INET6))
ifname ? "/conf/" : "", strempty(ifname), return -EAFNOSUPPORT;
property[0] == '/' ? "" : "/", property);
r = read_full_virtual_file(p, &value, NULL); if (ifname) {
if (r < 0) if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL))
return r; return -EINVAL;
truncate_nl(value); p = strjoina("net/", af_to_ipv4_ipv6(af), "/conf/", ifname, "/", property);
if (ret) } else
*ret = TAKE_PTR(value); p = strjoina("net/", af_to_ipv4_ipv6(af), "/", property);
return r; 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)) { FOREACH_DIRENT(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
char *filename; 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; const char *suffix, *dst = NULL;
bool valid_unit_name; bool valid_unit_name;

View File

@ -69,8 +69,8 @@ typedef struct {
BOOLEAN auto_entries; BOOLEAN auto_entries;
BOOLEAN auto_firmware; BOOLEAN auto_firmware;
BOOLEAN force_menu; BOOLEAN force_menu;
UINTN console_mode; INT64 console_mode;
enum console_mode_change_type console_mode_change; INT64 console_mode_efivar;
RandomSeedMode random_seed_mode; RandomSeedMode random_seed_mode;
} Config; } Config;
@ -370,13 +370,13 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
UINTN timeout; UINTN timeout;
BOOLEAN modevar; BOOLEAN modevar;
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL; _cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
UINTN x, y; UINTN x_max, y_max;
assert(config); assert(config);
assert(loaded_image_path); assert(loaded_image_path);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, COLOR_NORMAL); clear_screen(COLOR_NORMAL);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); console_query_mode(&x_max, &y_max);
Print(L"systemd-boot version: " GIT_VERSION "\n"); Print(L"systemd-boot version: " GIT_VERSION "\n");
Print(L"architecture: " EFI_MACHINE_TYPE_NAME "\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"UEFI specification: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
Print(L"firmware vendor: %s\n", ST->FirmwareVendor); Print(L"firmware vendor: %s\n", ST->FirmwareVendor);
Print(L"firmware version: %d.%02d\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); Print(L"firmware version: %d.%02d\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
Print(L"console mode: %d/%ld\n", ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - 1LL);
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_max, y_max);
Print(L"console size: %d x %d\n", x, y);
Print(L"SecureBoot: %s\n", yes_no(secure_boot_enabled())); Print(L"SecureBoot: %s\n", yes_no(secure_boot_enabled()));
if (efivar_get_boolean_u8(EFI_GLOBAL_GUID, L"SetupMode", &modevar) == EFI_SUCCESS) 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"); Print(L"\n--- press key ---\n\n");
console_key_read(&key, 0); console_key_read(&key, 0);
} }
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
} }
static BOOLEAN menu_run( static BOOLEAN menu_run(
@ -513,50 +509,43 @@ static BOOLEAN menu_run(
assert(loaded_image_path); assert(loaded_image_path);
EFI_STATUS err; EFI_STATUS err;
UINTN visible_max; UINTN visible_max = 0;
UINTN idx_highlight = config->idx_default; UINTN idx_highlight = config->idx_default;
UINTN idx_highlight_prev = 0; UINTN idx_highlight_prev = 0;
UINTN idx_first; UINTN idx_first = 0, idx_last = 0;
UINTN idx_last; BOOLEAN new_mode = TRUE, clear = TRUE;
BOOLEAN refresh = TRUE; BOOLEAN refresh = TRUE, highlight = FALSE;
BOOLEAN highlight = FALSE; UINTN x_start = 0, y_start = 0, y_status = 0;
UINTN line_width = 0; UINTN x_max, y_max;
UINTN entry_padding = 3; CHAR16 **lines = NULL, *status = NULL, *clearline = NULL;
CHAR16 **lines;
UINTN x_start;
UINTN y_start;
UINTN x_max;
UINTN y_max;
CHAR16 *status = NULL;
CHAR16 *clearline;
UINTN timeout_remain = config->timeout_sec; UINTN timeout_remain = config->timeout_sec;
INT16 idx; INT16 idx;
BOOLEAN exit = FALSE; BOOLEAN exit = FALSE, run = TRUE;
BOOLEAN run = TRUE; INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
graphics_mode(FALSE); graphics_mode(FALSE);
uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, 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->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 */ /* draw a single character to make ClearScreen work on some firmware */
Print(L" "); Print(L" ");
if (config->console_mode_change != CONSOLE_MODE_KEEP) { err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
err = console_set_mode(&config->console_mode, config->console_mode_change); config->console_mode_efivar : config->console_mode);
if (EFI_ERROR(err)) { if (EFI_ERROR(err)) {
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); clear_screen(COLOR_NORMAL);
log_error_stall(L"Error switching console mode to %lu: %r", (UINT64)config->console_mode, err); log_error_stall(L"Error switching console mode: %r", 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);
if (EFI_ERROR(err)) {
x_max = 80;
y_max = 25;
} }
while (!exit) {
UINT64 key;
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; visible_max = y_max - 2;
/* Drawing entries starts at idx_first until idx_last. We want to make /* Drawing entries starts at idx_first until idx_last. We want to make
@ -583,13 +572,23 @@ static BOOLEAN menu_run(
else else
y_start = 0; 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 */ /* menu entries title lines */
lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count); lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count);
for (UINTN i = 0; i < config->entry_count; i++) { for (UINTN i = 0; i < config->entry_count; i++) {
UINTN j; UINTN j, padding;
lines[i] = AllocatePool(((line_width + 1) * sizeof(CHAR16))); lines[i] = AllocatePool(((line_width + 1) * sizeof(CHAR16)));
UINTN padding = (line_width - MIN(StrLen(config->entries[i]->title_show), line_width)) / 2; padding = (line_width - MIN(StrLen(config->entries[i]->title_show), line_width)) / 2;
for (j = 0; j < padding; j++) for (j = 0; j < padding; j++)
lines[i][j] = ' '; lines[i][j] = ' ';
@ -607,13 +606,18 @@ static BOOLEAN menu_run(
clearline[i] = ' '; clearline[i] = ' ';
clearline[x_max] = 0; clearline[x_max] = 0;
while (!exit) { new_mode = FALSE;
UINT64 key; clear = TRUE;
}
if (clear) {
clear_screen(COLOR_NORMAL);
clear = FALSE;
refresh = TRUE;
}
if (refresh) { if (refresh) {
for (UINTN i = 0; i < config->entry_count; i++) { for (UINTN i = idx_first; i <= idx_last && i < config->entry_count; i++) {
if (i < idx_first || i > idx_last)
continue;
print_at(x_start, y_start + i - idx_first, print_at(x_start, y_start + i - idx_first,
(i == idx_highlight) ? COLOR_HIGHLIGHT : COLOR_ENTRY, (i == idx_highlight) ? COLOR_HIGHLIGHT : COLOR_ENTRY,
lines[i]); lines[i]);
@ -649,7 +653,7 @@ static BOOLEAN menu_run(
x = (x_max - len) / 2; x = (x_max - len) / 2;
else else
x = 0; 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, status);
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len); uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len);
} }
@ -671,7 +675,7 @@ static BOOLEAN menu_run(
if (status) { if (status) {
FreePool(status); FreePool(status);
status = NULL; 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; idx_highlight_prev = idx_highlight;
@ -733,7 +737,7 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'H'): case KEYPRESS(0, 0, 'H'):
case KEYPRESS(0, 0, '?'): case KEYPRESS(0, 0, '?'):
/* This must stay below 80 characters! Q/v/Ctrl+l deliberately not advertised. */ /* 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; break;
case KEYPRESS(0, 0, 'Q'): 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. * 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 * Since we cannot paint the last character of the edit line, we simply start
* at x-offset 1 for symmetry. */ * at x-offset 1 for symmetry. */
print_at(1, y_max - 1, COLOR_EDIT, 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_max-1); exit = line_edit(config->entries[idx_highlight]->options, &config->options_edit, x_max - 2, y_status);
print_at(1, y_max - 1, COLOR_NORMAL, clearline + 2); print_at(1, y_status, COLOR_NORMAL, clearline + 2);
break; break;
case KEYPRESS(0, 0, 'v'): case KEYPRESS(0, 0, 'v'):
@ -827,12 +831,35 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'p'): case KEYPRESS(0, 0, 'p'):
case KEYPRESS(0, 0, 'P'): case KEYPRESS(0, 0, 'P'):
print_status(config, loaded_image_path); print_status(config, loaded_image_path);
refresh = TRUE; clear = TRUE;
break; break;
case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'): case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'):
case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('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; break;
default: default:
@ -860,13 +887,23 @@ static BOOLEAN menu_run(
*chosen_entry = config->entries[idx_highlight]; *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++) for (UINTN i = 0; i < config->entry_count; i++)
FreePool(lines[i]); FreePool(lines[i]);
FreePool(lines); FreePool(lines);
FreePool(clearline); FreePool(clearline);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, COLOR_NORMAL); clear_screen(COLOR_NORMAL);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
return run; 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 *)"console-mode", key) == 0) {
if (strcmpa((CHAR8 *)"auto", value) == 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) 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) else if (strcmpa((CHAR8 *)"keep", value) == 0)
config->console_mode_change = CONSOLE_MODE_KEEP; config->console_mode = CONSOLE_MODE_KEEP;
else { else {
_cleanup_freepool_ CHAR16 *s = NULL; _cleanup_freepool_ CHAR16 *s = NULL;
s = stra_to_str(value); s = stra_to_str(value);
config->console_mode = Atoi(s); config->console_mode = MIN(Atoi(s), (UINTN)CONSOLE_MODE_RANGE_MAX);
config->console_mode_change = CONSOLE_MODE_SET;
} }
continue; continue;
@ -1410,7 +1446,7 @@ static VOID config_entry_add_from_file(
static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) { static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
_cleanup_freepool_ CHAR8 *content = NULL; _cleanup_freepool_ CHAR8 *content = NULL;
UINTN sec; UINTN value;
EFI_STATUS err; EFI_STATUS err;
assert(root_dir); assert(root_dir);
@ -1421,27 +1457,33 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
.auto_firmware = TRUE, .auto_firmware = TRUE,
.random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN, .random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN,
.idx_default_efivar = -1, .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); err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL);
if (!EFI_ERROR(err)) if (!EFI_ERROR(err))
config_defaults_load_from_file(config, content); 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)) { if (!EFI_ERROR(err)) {
config->timeout_sec_efivar = sec > INTN_MAX ? INTN_MAX : sec; config->timeout_sec_efivar = value > INTN_MAX ? INTN_MAX : value;
config->timeout_sec = sec; config->timeout_sec = value;
} else } else
config->timeout_sec_efivar = -1; 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)) { if (!EFI_ERROR(err)) {
/* Unset variable now, after all it's "one shot". */ /* Unset variable now, after all it's "one shot". */
(void) efivar_set(LOADER_GUID, L"LoaderConfigTimeoutOneShot", NULL, EFI_VARIABLE_NON_VOLATILE); (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 */ 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( static VOID config_load_entries(

View File

@ -8,6 +8,9 @@
#define SYSTEM_FONT_WIDTH 8 #define SYSTEM_FONT_WIDTH 8
#define SYSTEM_FONT_HEIGHT 19 #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 \ #define EFI_SIMPLE_TEXT_INPUT_EX_GUID \
&(const EFI_GUID) EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_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; return EFI_SUCCESS;
} }
static EFI_STATUS change_mode(UINTN mode) { static EFI_STATUS change_mode(INT64 mode) {
EFI_STATUS err; 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); 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 /* Something went wrong. Output is probably borked, so try to revert to previous mode. */
* and breaks console output. */ if (!EFI_ERROR(uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, old_mode)))
if (EFI_ERROR(err) && mode == 1) return err;
uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, (UINTN)0);
/* 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; return err;
} }
static UINT64 text_area_from_font_size(void) { static INT64 get_auto_mode(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;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
EFI_STATUS err; EFI_STATUS err;
BOOLEAN keep = FALSE;
assert(mode); err = LibLocateProtocol(&GraphicsOutputProtocol, (VOID **)&GraphicsOutput);
err = LibLocateProtocol((EFI_GUID*) &GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
if (!EFI_ERROR(err) && GraphicsOutput->Mode && GraphicsOutput->Mode->Info) { 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 /* 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 * (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, * 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. */ * then assume the text is readable and keep the text mode. */
else { else {
screen_area = (UINT64)Info->HorizontalResolution * (UINT64)Info->VerticalResolution; UINT64 text_area;
text_area = text_area_from_font_size(); 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) if (text_area != 0 && screen_area/text_area < VIEWPORT_RATIO)
keep = TRUE; keep = TRUE;
} }
}
if (keep) { if (keep)
/* Just clear the screen instead of changing the mode and return. */ return ST->ConOut->Mode->Mode;
*mode = ST->ConOut->Mode->Mode;
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
return EFI_SUCCESS;
} }
/* If we reached here, then we have a high resolution screen and the text /* 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 * standard mode, which is provided by the device manufacturer, so it should
* be a good mode. * be a good mode.
* Note: MaxMode is the number of modes, not the last mode. */ * Note: MaxMode is the number of modes, not the last mode. */
if (ST->ConOut->Mode->MaxMode > 2) if (ST->ConOut->Mode->MaxMode > CONSOLE_MODE_FIRMWARE_FIRST)
*mode = 2; return CONSOLE_MODE_FIRMWARE_FIRST;
/* Try again with mode different than zero (assume user requests /* Try again with mode different than zero (assume user requests
* auto mode due to some problem with mode zero). */ * auto mode due to some problem with mode zero). */
else if (ST->ConOut->Mode->MaxMode == 2) if (ST->ConOut->Mode->MaxMode > CONSOLE_MODE_80_50)
*mode = 1; return CONSOLE_MODE_80_50;
/* Else force mode change to zero. */
else
*mode = 0;
return change_mode(*mode); return CONSOLE_MODE_80_25;
} }
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how) { EFI_STATUS console_set_mode(INT64 mode) {
assert(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) case CONSOLE_MODE_NEXT:
return mode_auto(mode); 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. */ /* Note: MaxMode is the number of modes, not the last mode. */
if (ST->ConOut->Mode->MaxMode > 0) return change_mode(ST->ConOut->Mode->MaxMode - 1LL);
*mode = ST->ConOut->Mode->MaxMode-1;
else default:
*mode = 0; return change_mode(mode);
}
} }
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 err;
} }

View File

@ -9,12 +9,23 @@
#define KEYCHAR(k) ((k) & 0xffff) #define KEYCHAR(k) ((k) & 0xffff)
#define CHAR_CTRL(c) ((c) - 'a' + 1) #define CHAR_CTRL(c) ((c) - 'a' + 1)
enum console_mode_change_type { enum {
CONSOLE_MODE_KEEP = 0, /* Console mode is a INT32 in EFI. We use INT64 to make room for our special values. */
CONSOLE_MODE_SET, 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_AUTO,
CONSOLE_MODE_MAX, CONSOLE_MODE_FIRMWARE_MAX, /* 'max' in config. */
}; };
EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec); 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->SetAttribute, 2, ST->ConOut, attr);
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)str); 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 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 */ /* 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 /* If we will deserialize make sure that during enumeration this is already known, so we increase the
* counter here already */ * counter here already */
@ -3237,7 +3237,7 @@ int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
} }
int manager_reload(Manager *m) { 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_fdset_free_ FDSet *fds = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
int r; int r;

View File

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

View File

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

View File

@ -14,7 +14,7 @@
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL; _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; int r;
log_setup(); log_setup();

View File

@ -166,10 +166,10 @@ static void context_read_os_release(Context *c) {
c->etc_os_release_stat = current_stat; c->etc_os_release_stat = current_stat;
} }
static bool valid_chassis(const char *chassis) { static const char* valid_chassis(const char *chassis) {
assert(chassis); assert(chassis);
return nulstr_contains( return nulstr_get(
"vm\0" "vm\0"
"container\0" "container\0"
"desktop\0" "desktop\0"
@ -190,6 +190,7 @@ static bool valid_deployment(const char *deployment) {
} }
static const char* fallback_chassis(void) { static const char* fallback_chassis(void) {
const char *chassis;
char *type; char *type;
unsigned t; unsigned t;
int v, r; int v, r;
@ -261,14 +262,14 @@ try_acpi:
r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type); r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
if (r < 0) { if (r < 0) {
log_debug_errno(r, "Failed read ACPI PM profile, ignoring: %m"); log_debug_errno(r, "Failed read ACPI PM profile, ignoring: %m");
return NULL; goto try_devicetree;
} }
r = safe_atou(type, &t); r = safe_atou(type, &t);
free(type); free(type);
if (r < 0) { if (r < 0) {
log_debug_errno(r, "Failed parse ACPI PM profile, ignoring: %m"); 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. /* We only list the really obvious cases here as the ACPI data is not really super reliable.
@ -300,9 +301,26 @@ try_acpi:
log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t); log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t);
} }
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; 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) { static char* context_fallback_icon_name(Context *c) {
const char *chassis; const char *chassis;

View File

@ -311,7 +311,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(server_done) Server server = { .epoll_fd = -1 }; _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; int r, n;
if (argc > 1) 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) { static int run(int argc, char **argv) {
_cleanup_(journal_remote_server_destroy) RemoteServer s = {}; _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_(erase_and_freep) char *key = NULL;
_cleanup_free_ char *cert = NULL, *trust = NULL; _cleanup_free_ char *cert = NULL, *trust = NULL;
int r; 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 journal_remote_add_raw_socket(RemoteServer *s, int fd) {
int r; int r;
_cleanup_close_ int fd_ = fd; _unused_ _cleanup_close_ int fd_ = fd;
char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1]; char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
assert(fd >= 0); assert(fd >= 0);

View File

@ -820,7 +820,7 @@ static int open_journal(sd_journal **j) {
static int run(int argc, char **argv) { static int run(int argc, char **argv) {
_cleanup_(destroy_uploader) Uploader u = {}; _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; bool use_journal;
int r; int r;

View File

@ -903,7 +903,7 @@ static void dispatch_message_real(
pid_t object_pid) { pid_t object_pid) {
char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; 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; uid_t journal_uid;
ClientContext *o; 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; properties = &device->properties;
if (value) { 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; int r;
r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops_free_free); 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_key);
TAKE_PTR(new_value); TAKE_PTR(new_value);
} else { } 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); 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) { 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; int r;
assert(device); assert(device);

View File

@ -53,7 +53,7 @@ static void test_catalog_import_invalid(void) {
} }
static void test_catalog_import_badid(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 = const char *input =
"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededede\n" \ "-- 0027229ca0644181a76c4e92458afaff dededededededededededededededede\n" \
"Subject: message\n" \ "Subject: message\n" \

View File

@ -703,7 +703,7 @@ bool manager_all_buttons_ignored(Manager *m) {
int manager_read_utmp(Manager *m) { int manager_read_utmp(Manager *m) {
#if ENABLE_UTMP #if ENABLE_UTMP
int r; int r;
_cleanup_(utxent_cleanup) bool utmpx = false; _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
assert(m); 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) { static void session_release_controller(Session *s, bool notify) {
_cleanup_free_ char *name = NULL; _unused_ _cleanup_free_ char *name = NULL;
SessionDevice *sd; SessionDevice *sd;
if (!s->controller) if (!s->controller)

View File

@ -1157,7 +1157,7 @@ static int manager_run(Manager *m) {
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_unrefp) Manager *m = NULL; _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; int r;
log_set_facility(LOG_AUTH); log_set_facility(LOG_AUTH);

View File

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

View File

@ -19,7 +19,7 @@
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL; _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; int r;
log_setup(); log_setup();

View File

@ -195,7 +195,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL; _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; int r;
log_setup(); log_setup();

View File

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

View File

@ -303,7 +303,7 @@ enum nss_status userdb_getgrnam(
} }
if (!g) { if (!g) {
_cleanup_(_nss_systemd_unblockp) bool blocked = false; _unused_ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
if (strv_isempty(members)) if (strv_isempty(members))
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
@ -365,7 +365,7 @@ enum nss_status userdb_getgrgid(
} }
if (!g) { 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 /* 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 * 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) { 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 /* 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). */ * 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; _cleanup_set_free_ Set *targets = NULL;
bool in_post_action_delay = false; bool in_post_action_delay = false;
Manager *m = userdata; Manager *m = userdata;

View File

@ -116,7 +116,7 @@ static int parse_argv(int argc, char *argv[]) {
} }
static int run(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_(manager_freep) Manager *m = NULL;
_cleanup_free_ char *swap = NULL; _cleanup_free_ char *swap = NULL;
unsigned long long s = 0; 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++) { for (size_t i = 0; i < context->n_free_areas; i++) {
FreeArea *a = context->free_areas[i]; FreeArea *a = context->free_areas[i];
uint64_t start, left; _unused_ uint64_t left;
uint64_t start;
if (a->after) { if (a->after) {
assert(a->after->offset != UINT64_MAX); 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); first = hashmap_get(c->by_key, i->key);
if (first) { 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. */ /* Keep a reference to the original key, while we manipulate the list. */
k = dns_resource_key_ref(first->key); 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) { 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; DnsTransaction *t;
int r; int r;
unsigned n = 0; unsigned n = 0;

View File

@ -23,7 +23,7 @@
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL; _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; int r;
log_setup(); log_setup();

View File

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

View File

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

View File

@ -25,7 +25,7 @@
#include "utmp-wtmp.h" #include "utmp-wtmp.h"
int utmp_get_runlevel(int *runlevel, int *previous) { 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 }; struct utmpx *found, lookup = { .ut_type = RUN_LVL };
const char *e; 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) { static int write_entry_utmp(const struct utmpx *store) {
_cleanup_(utxent_cleanup) bool utmpx = false; _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
assert(store); 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) { 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 = { struct utmpx lookup = {
.ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ .ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
}, store, store_wtmp, *found; }, store, store_wtmp, *found;
@ -340,7 +340,7 @@ int utmp_wall(
bool (*match_tty)(const char *tty, void *userdata), bool (*match_tty)(const char *tty, void *userdata),
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; _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
struct utmpx *u; struct utmpx *u;
int r; int r;

View File

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

View File

@ -1,10 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-id128.h"
#include "errno-util.h"
#include "hostname-util.h"
#include "strv.h" #include "strv.h"
#include "sysctl-util.h" #include "sysctl-util.h"
#include "tests.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", "a/b/c", "a/b/c", "a/b/c",
"a/b.c/d", "a/b.c/d", "a/b.c/d", "a/b.c/d",
@ -24,7 +28,7 @@ static void test_sysctl_normalize(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
const char **s, **expected; const char **s, **expected;
STRV_FOREACH_PAIR(s, expected, cases) { STRV_FOREACH_PAIR(s, expected, (const char**) cases) {
_cleanup_free_ char *t; _cleanup_free_ char *t;
assert_se(t = strdup(*s)); 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[]) { int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO); test_setup_logging(LOG_INFO);
test_sysctl_normalize(); test_sysctl_normalize();
test_sysctl_read();
return 0; return 0;
} }

View File

@ -87,7 +87,7 @@ settime:
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL; _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"; const char *user = "systemd-timesync";
uid_t uid, uid_current; uid_t uid, uid_current;
gid_t gid; gid_t gid;

View File

@ -338,7 +338,8 @@ static int process_and_watch_password_files(bool watch) {
_FD_MAX _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]; struct pollfd pollfd[_FD_MAX];
sigset_t mask; sigset_t mask;
int r; int r;

View File

@ -1136,7 +1136,8 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
manager_reload(manager); manager_reload(manager);
break; break;
case UDEV_CTRL_SET_ENV: { 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; const char *eq;
eq = strchr(value->buf, '='); eq = strchr(value->buf, '=');

View File

@ -24,7 +24,7 @@
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL; _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; int r;
log_setup(); log_setup();