1
0
mirror of https://github.com/systemd/systemd synced 2026-04-20 22:14:52 +02:00

Compare commits

...

40 Commits

Author SHA1 Message Date
Yu Watanabe
f3376ee8fa
Merge pull request #22487 from poettering/bootspec-source-flags
bootctl: show all discovered entries, but show state + type in details
2022-02-15 04:45:59 +09:00
Yu Watanabe
88586e5d32
Merge pull request #22508 from poettering/stat-ino-compare
stat-util: add new stat_inode_same() helper
2022-02-15 04:45:31 +09:00
Yu Watanabe
d1e7fa02ca
Merge pull request #22507 from poettering/id128-compare-tweaks
sd-id128: comparison tweaks
2022-02-15 04:40:53 +09:00
Lennart Poettering
1d7150ec7f docs: make clear that if you use threaded cgroups you need to do that two levels down from your delegated cgroup
Prompted by: #22486
2022-02-14 19:06:40 +00:00
Lennart Poettering
d6b218e742 sd-daemon: use path_join() instead of manual path concat 2022-02-14 17:27:24 +01:00
Lennart Poettering
c20c77eff8 coredump: fix inode check
When checking if we look at the root directory we actually need to
compare both st_dev *and* st_ino. The existing check only checked the
latter. Fix that.
2022-02-14 17:27:21 +01:00
Lennart Poettering
675e7fc22c fd-util: use ERRNO_IS_XYZ() macros where appropriate 2022-02-14 17:27:18 +01:00
Lennart Poettering
a9dac7a6dd tree-wide: port various places over to new stat_inode_same() helper 2022-02-14 17:27:14 +01:00
Lennart Poettering
38db6211b5 stat-util: add helper stat_inode_same() for comparing stat's st_dev/st_ino in one
We do this all over the place, hence let's add a simple helper that does
this and particularly carefully and thoroughly.
2022-02-14 17:27:09 +01:00
Luca Boccassi
d74da762a3
Merge pull request #22506 from poettering/devnum-zero-btrfs-block-dev
gpt-auto: some (primarily cosmetic) fixes to backing block device detection in gpt-auto-generator/sd-device
2022-02-14 16:17:04 +00:00
Luca Boccassi
bfba9946a1
Merge pull request #22445 from lnussel/logind
logind: post review fixes
2022-02-14 16:16:39 +00:00
Lennart Poettering
d5ac1d4e10 bootspec: avoid zero size VLA
apparently some checkers don't like that. Let's be entirely safe here,
and use malloc() based allocation, given that the entries are user
controlled.
2022-02-14 16:24:04 +01:00
Lennart Poettering
f63b5ad935 boot: suppress XBOOTLDR if same device as ESP when enumerating entries
On my local system I linked up the ESP and XBOOTLDR partitions, and
ended up with duplicate entries being listed. Try hard to detect that
and only enumerate entries in the ESP if it turns out that both dirs
have the same dev_t.

This should detect both bind mounted and symlinked cases and should make
our list output less confusing.
2022-02-14 16:24:04 +01:00
Lennart Poettering
5635040091 bootspec: make sure all return values are initialized on return of find_esp_and_warn()
THis makes sure that find_esp_and_warn() + find_xbootldr_and_warn()
follow our usual coding style that on success all return values are
initialized. We got that right in most successful codepaths out of these
functions, but missed the one where the paths are manually overwritten
via env vars.
2022-02-14 15:44:07 +01:00
Lennart Poettering
bb68205768 bootctl: show more information about boot entry state in list
Let's improve display of boot entries and show what type they have (i.e.
boot loader spec type 1, or type 2, or auto-discovered or reported by
boot loader), and in particular mark entries the boot loader discovered
but we can't find (i.e. that likely vanished, or possibly couldn't be
found due to a misconfiguration) and that the boot loader didn't find
but we see (which are new, or possibly also the result of
misconfiguraiton).

This is supposed to be a replacement for #22161, but instead of hiding
vanished entries, highlights them, which I think is more appropriate for
a low-level tool such bootctl.

Replaces: #22161 #22398
2022-02-14 15:44:07 +01:00
Lennart Poettering
a78e472dfd bootspec: also collect/mark the "selected" boot entry (i.e. the one currently booted)
it's helpful and easy, so let's do it
2022-02-14 15:44:07 +01:00
Lennart Poettering
d403d8f0d6 bootspec: also parse new 'beep' loader.conf variable 2022-02-14 15:44:07 +01:00
Lennart Poettering
fdc5c04299 bootspec: parse/show devicetree-overlay field too
It has been defined in the boot loader spec, and is the only field we
currently don't parse, hence fix that.
2022-02-14 15:44:07 +01:00
Lennart Poettering
4cddc18d0a update TODO 2022-02-14 15:44:07 +01:00
Lennart Poettering
736783d420 bootspec: port one more use of basename() to path_extract_filename() 2022-02-14 15:44:07 +01:00
Lennart Poettering
9951736b7f Revert "bootctl: Ignore boot entries (continue #22041)" 2022-02-14 15:44:07 +01:00
Lennart Poettering
93e0d3204c veritysetup: whitespace fix 2022-02-14 15:14:17 +01:00
Lennart Poettering
fe9bd5ad36 homed: use SD_ID128_TO_UUID_STRING() at one more place 2022-02-14 15:14:14 +01:00
Lennart Poettering
e46433bb92 tree-wide: use id128_equal_string() at various places 2022-02-14 15:14:11 +01:00
Lennart Poettering
75a505c600 id128-util: add new helper id128_equal_string()
Quite often we compare uuids/id128 formatted as strings with specific
values. So far we usually used streq() for that. let's add a new
explicit helper for this in id128_equal_string() that compares a string
with an sd_id128_t and is more robust than a simple string comparison.
Moreover, we can mroe easily reuse the various defines we have for
specific UUIDs, for example those from gpt.h.
2022-02-14 15:14:03 +01:00
Lennart Poettering
b74163607b sd128: export sd_id128_to_uuid_string()
We expose various other forms of UUID helpers already, i.e.
SD_ID128_UUID_FORMAT_STR and SD_ID128_MAKE_UUID_STR(), and we parse
UUIDs, hence add a high-level helper for formatting UUIDs too.

This doesn't add any new code, it just moves some helpers
id128-util.[ch] → sd-id128.[ch], to make them public.
2022-02-14 15:13:23 +01:00
Frantisek Sumsal
fdf9de694f
Merge pull request #22505 from mrc0mmand/more-coverage-tweaks
A couple of coverage-related tweaks
2022-02-14 13:51:08 +00:00
Yu Watanabe
42672c80dc test: check if running in container earlier 2022-02-14 13:46:17 +00:00
Luca Boccassi
d0ebe2a835
Merge pull request #22496 from yuwata/network-cleanups-keep-configuration
network: cleanups for KeepConfiguration= setting
2022-02-14 13:17:23 +00:00
Lennart Poettering
d5cb053cd9 gpt-auto: properly handle case where we can't determine devno of /usr/ fs
get_block_device_harder() returns == 0 if the fs is valid, but it is not
backed by a single devno. (As opposed to returning > 0 if the devno is
valid). Let's catch this case and log a clear message, and don't bother
open the device in that case.

This is mostly cosmetical, as either way, systemd-gpt-auto-generator
doesn't work in scenarios like that.

Prompted-by: #22504
2022-02-14 13:40:59 +01:00
Lennart Poettering
f1ad2c9238 sd-device: refuse opening device mit major/minor of zero early
device nodes with 0 dev_t are not real (and for that reason such inodes
are used as whiteouts in overlayfs, for example), hence refuse them
early. It seems wrong going to sysfs for something we know can't exist
anyway.
2022-02-14 13:40:56 +01:00
Frantisek Sumsal
d282e57e2a test: check for (possibly) missing test coverage
If the test logs contain lines like:

```
...systemd-resolved[735885]: profiling:/systemd-meson-build/src/shared/libsystemd-shared-250.a.p/base-filesystem.c.gcda:Cannot open
```

it means we're possibly missing some coverage since gcov can't write the stats,
usually due to the sandbox being too restrictive (e.g. ProtectSystem=yes,
ProtectHome=yes) or the $BUILD_DIR being inaccessible to non-root users.
2022-02-14 12:20:02 +01:00
Frantisek Sumsal
e4c822e9ac test: set ACLs for the build dir when built with coverage
Otherwise unprivileged processes (like systemd-resolved) can't write
coverage data.
2022-02-14 11:58:54 +01:00
Ludwig Nussel
2a3a5288cb systemctl: fix halt -f
Commit adefc8789b always asks logind for shutdown first. So I broke halt
-f which is supposed to issue a direct syscall in that case.
2022-02-14 09:35:12 +01:00
Ludwig Nussel
54141d8ddd logind: more verbose struct initialization 2022-02-14 09:35:12 +01:00
Ludwig Nussel
1831759a70 logind: increase max wall message length to 4096 2022-02-14 09:35:12 +01:00
Ludwig Nussel
d2fc0ecf9a logind: style fixes 2022-02-14 09:35:12 +01:00
Ludwig Nussel
138224fc80 logind: add handle enum to struct
Avoid pointer arithmetic at the expense of repeating the enum value
in the struct.
2022-02-14 09:35:12 +01:00
Yu Watanabe
81db4f3dd8 network: drop managed configs on reconfigure when KeepConfiguration=yes
Otherwise, the managed configs, that is addresses, routes and so on
configured by the previously assigned .network file will not be dropped
on reconfiguring the interface.
2022-02-13 20:01:42 +09:00
Yu Watanabe
07c160a65c network: drop redundant condition
The function `link_drop_foreign_addresses()` is only called in
`link_drop_foreign_config()`, and the same condition is located in the
caller.
2022-02-13 20:01:29 +09:00
49 changed files with 687 additions and 426 deletions

2
TODO
View File

@ -78,6 +78,8 @@ Janitorial Clean-ups:
Features: Features:
* bootspec: remove tries counter from boot entry ids
* automatically ignore threaded cgroups in cg_xyz(). * automatically ignore threaded cgroups in cg_xyz().
* add linker script that implicitly adds symbol for build ID and new coredump * add linker script that implicitly adds symbol for build ID and new coredump

View File

@ -266,6 +266,15 @@ tree by the time it notifies the service manager about start-up readiness, so
that the service's main cgroup is definitely an inner node by the time the that the service's main cgroup is definitely an inner node by the time the
service manager might start `ExecStartPost=`.) service manager might start `ExecStartPost=`.)
(Also note, if you intend to use "threaded" cgroups — as added in Linux 4.14 —,
then you should do that *two* levels down from the main service cgroup your
turned delegation on for. Why that? You need one level so that systemd can
properly create the `.control` subgroup, as described above. But that one
cannot be threaded, since that would mean `.control` has to be threaded too —
this is a requirement of threaded cgroups: either a cgroup and all its siblings
are threaded or none , but systemd expects it to be a regular cgroup. Thus you
have to nest a second cgroup beneath it which then can be threaded.)
## Three Scenarios ## Three Scenarios
Let's say you write a container manager, and you wonder what to do regarding Let's say you write a container manager, and you wonder what to do regarding

View File

@ -641,7 +641,12 @@ manpages = [
['sd_id128_randomize', '3', [], ''], ['sd_id128_randomize', '3', [], ''],
['sd_id128_to_string', ['sd_id128_to_string',
'3', '3',
['SD_ID128_STRING_MAX', 'SD_ID128_TO_STRING', 'sd_id128_from_string'], ['SD_ID128_STRING_MAX',
'SD_ID128_TO_STRING',
'SD_ID128_TO_UUID_STRING',
'SD_ID128_UUID_STRING_MAX',
'sd_id128_from_string',
'sd_id128_to_uuid_string'],
''], ''],
['sd_is_fifo', ['sd_is_fifo',
'3', '3',

View File

@ -18,8 +18,11 @@
<refnamediv> <refnamediv>
<refname>sd_id128_to_string</refname> <refname>sd_id128_to_string</refname>
<refname>SD_ID128_TO_STRING</refname> <refname>SD_ID128_TO_STRING</refname>
<refname>sd_id128_from_string</refname>
<refname>SD_ID128_STRING_MAX</refname> <refname>SD_ID128_STRING_MAX</refname>
<refname>sd_id128_to_uuid_string</refname>
<refname>SD_ID128_TO_UUID_STRING</refname>
<refname>SD_ID128_UUID_STRING_MAX</refname>
<refname>sd_id128_from_string</refname>
<refpurpose>Format or parse 128-bit IDs as strings</refpurpose> <refpurpose>Format or parse 128-bit IDs as strings</refpurpose>
</refnamediv> </refnamediv>
@ -29,13 +32,22 @@
<funcsynopsisinfo>#define SD_ID128_STRING_MAX 33U</funcsynopsisinfo> <funcsynopsisinfo>#define SD_ID128_STRING_MAX 33U</funcsynopsisinfo>
<funcsynopsisinfo>#define SD_ID128_UUID_STRING_MAX 37U</funcsynopsisinfo>
<funcsynopsisinfo>#define SD_ID128_TO_STRING(id) …</funcsynopsisinfo> <funcsynopsisinfo>#define SD_ID128_TO_STRING(id) …</funcsynopsisinfo>
<funcsynopsisinfo>#define SD_ID128_TO_UUID_STRING(id) …</funcsynopsisinfo>
<funcprototype> <funcprototype>
<funcdef>char *<function>sd_id128_to_string</function></funcdef> <funcdef>char *<function>sd_id128_to_string</function></funcdef>
<paramdef>sd_id128_t <parameter>id</parameter>, char <parameter>s</parameter>[static SD_ID128_STRING_MAX]</paramdef> <paramdef>sd_id128_t <parameter>id</parameter>, char <parameter>s</parameter>[static SD_ID128_STRING_MAX]</paramdef>
</funcprototype> </funcprototype>
<funcprototype>
<funcdef>char *<function>sd_id128_uuid_string</function></funcdef>
<paramdef>sd_id128_t <parameter>id</parameter>, char <parameter>s</parameter>[static SD_ID128_UUID_STRING_MAX]</paramdef>
</funcprototype>
<funcprototype> <funcprototype>
<funcdef>int <function>sd_id128_from_string</function></funcdef> <funcdef>int <function>sd_id128_from_string</function></funcdef>
<paramdef>const char *<parameter>s</parameter>, sd_id128_t *<parameter>ret</parameter></paramdef> <paramdef>const char *<parameter>s</parameter>, sd_id128_t *<parameter>ret</parameter></paramdef>
@ -58,6 +70,10 @@
which remains valid until the end of the current code block. This is usually the simplest way to acquire which remains valid until the end of the current code block. This is usually the simplest way to acquire
a string representation of a 128-bit ID in a buffer that is valid in the current code block.</para> a string representation of a 128-bit ID in a buffer that is valid in the current code block.</para>
<para><function>sd_id128_to_uuid_string()</function> and <function>SD_ID128_TO_UUID_STRING()</function>
are similar to these two functions/macros, but format the 128bit values as RFC4122 UUIDs, i.e. a series
of 36 lowercase hexadeciaml digits and dashes, terminated by a <constant>NUL</constant> byte.</para>
<para><function>sd_id128_from_string()</function> implements the reverse operation: it takes a 33 <para><function>sd_id128_from_string()</function> implements the reverse operation: it takes a 33
character string with 32 hexadecimal digits (either lowercase or uppercase, terminated by character string with 32 hexadecimal digits (either lowercase or uppercase, terminated by
<constant>NUL</constant>) and parses them back into a 128-bit ID returned in <constant>NUL</constant>) and parses them back into a 128-bit ID returned in
@ -65,7 +81,7 @@
ID formatted as RFC UUID. If <parameter>ret</parameter> is passed as <constant>NULL</constant> the ID formatted as RFC UUID. If <parameter>ret</parameter> is passed as <constant>NULL</constant> the
function will validate the passed ID string, but not actually return it in parsed form.</para> function will validate the passed ID string, but not actually return it in parsed form.</para>
<para>Note that when parsing 37 character UUIDs this is done strictly in Big Endian byte order, <para>Note that when formatting and parsing 36 character UUIDs this is done strictly in Big Endian byte order,
i.e. according to <ulink url="https://tools.ietf.org/html/rfc4122">RFC4122</ulink> Variant 1 rules, even i.e. according to <ulink url="https://tools.ietf.org/html/rfc4122">RFC4122</ulink> Variant 1 rules, even
if the UUID encodes a different variant. This matches behaviour in various other Linux userspace if the UUID encodes a different variant. This matches behaviour in various other Linux userspace
tools. It's probably wise to avoid UUIDs of other variant types.</para> tools. It's probably wise to avoid UUIDs of other variant types.</para>

View File

@ -417,14 +417,11 @@ int same_fd(int a, int b) {
assert(a >= 0); assert(a >= 0);
assert(b >= 0); assert(b >= 0);
/* Compares two file descriptors. Note that semantics are /* Compares two file descriptors. Note that semantics are quite different depending on whether we
* quite different depending on whether we have kcmp() or we * have kcmp() or we don't. If we have kcmp() this will only return true for dup()ed file
* don't. If we have kcmp() this will only return true for * descriptors, but not otherwise. If we don't have kcmp() this will also return true for two fds of
* dup()ed file descriptors, but not otherwise. If we don't * the same file, created by separate open() calls. Since we use this call mostly for filtering out
* have kcmp() this will also return true for two fds of the same * duplicates in the fd store this difference hopefully doesn't matter too much. */
* file, created by separate open() calls. Since we use this
* call mostly for filtering out duplicates in the fd store
* this difference hopefully doesn't matter too much. */
if (a == b) if (a == b)
return true; return true;
@ -436,7 +433,7 @@ int same_fd(int a, int b) {
return true; return true;
if (r > 0) if (r > 0)
return false; return false;
if (!IN_SET(errno, ENOSYS, EACCES, EPERM)) if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno; return -errno;
/* We don't have kcmp(), use fstat() instead. */ /* We don't have kcmp(), use fstat() instead. */
@ -446,23 +443,17 @@ int same_fd(int a, int b) {
if (fstat(b, &stb) < 0) if (fstat(b, &stb) < 0)
return -errno; return -errno;
if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) if (!stat_inode_same(&sta, &stb))
return false; return false;
/* We consider all device fds different, since two device fds /* We consider all device fds different, since two device fds might refer to quite different device
* might refer to quite different device contexts even though * contexts even though they share the same inode and backing dev_t. */
* they share the same inode and backing dev_t. */
if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
return false; return false;
if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) /* The fds refer to the same inode on disk, let's also check if they have the same fd flags. This is
return false; * useful to distinguish the read and write side of a pipe created with pipe(). */
/* The fds refer to the same inode on disk, let's also check
* if they have the same fd flags. This is useful to
* distinguish the read and write side of a pipe created with
* pipe(). */
fa = fcntl(a, F_GETFL); fa = fcntl(a, F_GETFL);
if (fa < 0) if (fa < 0)
return -errno; return -errno;

View File

@ -856,8 +856,7 @@ int conservative_renameat(
if (fstat(new_fd, &new_stat) < 0) if (fstat(new_fd, &new_stat) < 0)
goto do_rename; goto do_rename;
if (new_stat.st_ino == old_stat.st_ino && if (stat_inode_same(&new_stat, &old_stat))
new_stat.st_dev == old_stat.st_dev)
goto is_same; goto is_same;
if (old_stat.st_mode != new_stat.st_mode || if (old_stat.st_mode != new_stat.st_mode ||

View File

@ -298,10 +298,8 @@ fallback_fstat:
if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
return -errno; return -errno;
/* A directory with same device and inode as its parent? Must /* A directory with same device and inode as its parent? Must be the root directory */
* be the root directory */ if (stat_inode_same(&a, &b))
if (a.st_dev == b.st_dev &&
a.st_ino == b.st_ino)
return 1; return 1;
return check_st_dev && (a.st_dev != b.st_dev); return check_st_dev && (a.st_dev != b.st_dev);

View File

@ -185,8 +185,7 @@ int files_same(const char *filea, const char *fileb, int flags) {
if (fstatat(AT_FDCWD, fileb, &b, flags) < 0) if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
return -errno; return -errno;
return a.st_dev == b.st_dev && return stat_inode_same(&a, &b);
a.st_ino == b.st_ino;
} }
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
@ -417,6 +416,18 @@ int proc_mounted(void) {
return r; return r;
} }
bool stat_inode_same(const struct stat *a, const struct stat *b) {
/* Returns if the specified stat structure references the same (though possibly modified) inode. Does
* a thorough check, comparing inode nr, backing device and if the inode is still of the same type. */
return a && b &&
(a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
a->st_dev == b->st_dev &&
a->st_ino == b->st_ino;
}
bool stat_inode_unmodified(const struct stat *a, const struct stat *b) { bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
/* Returns if the specified stat structures reference the same, unmodified inode. This check tries to /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
@ -428,14 +439,10 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
* about contents of the file. The purpose here is to detect file contents changes, and nothing * about contents of the file. The purpose here is to detect file contents changes, and nothing
* else. */ * else. */
return a && b && return stat_inode_same(a, b) &&
(a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
a->st_mtim.tv_sec == b->st_mtim.tv_sec && a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
a->st_mtim.tv_nsec == b->st_mtim.tv_nsec && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
(!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */ (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
a->st_dev == b->st_dev &&
a->st_ino == b->st_ino &&
(!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */ (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
} }

View File

@ -92,6 +92,7 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
int proc_mounted(void); int proc_mounted(void);
bool stat_inode_same(const struct stat *a, const struct stat *b);
bool stat_inode_unmodified(const struct stat *a, const struct stat *b); bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx); int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
@ -114,3 +115,9 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
struct new_statx nsx; \ struct new_statx nsx; \
} var } var
#endif #endif
static inline bool devid_set_and_equal(dev_t a, dev_t b) {
/* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
* know" and we'll return false */
return a == b && a != 0;
}

View File

@ -14,6 +14,7 @@
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h" #include "path-util.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "stat-util.h"
#include "sync-util.h" #include "sync-util.h"
#include "terminal-util.h" #include "terminal-util.h"
#include "util.h" #include "util.h"
@ -98,17 +99,18 @@ static int parse_argv(int argc, char *argv[]) {
static int acquire_path(void) { static int acquire_path(void) {
_cleanup_free_ char *esp_path = NULL, *xbootldr_path = NULL; _cleanup_free_ char *esp_path = NULL, *xbootldr_path = NULL;
dev_t esp_devid = 0, xbootldr_devid = 0;
char **a; char **a;
int r; int r;
if (!strv_isempty(arg_path)) if (!strv_isempty(arg_path))
return 0; return 0;
r = find_esp_and_warn(NULL, false, &esp_path, NULL, NULL, NULL, NULL); r = find_esp_and_warn(NULL, /* unprivileged_mode= */ false, &esp_path, NULL, NULL, NULL, NULL, &esp_devid);
if (r < 0 && r != -ENOKEY) /* ENOKEY means not found, and is the only error the function won't log about on its own */ if (r < 0 && r != -ENOKEY) /* ENOKEY means not found, and is the only error the function won't log about on its own */
return r; return r;
r = find_xbootldr_and_warn(NULL, false, &xbootldr_path, NULL); r = find_xbootldr_and_warn(NULL, /* unprivileged_mode= */ false, &xbootldr_path, NULL, &xbootldr_devid);
if (r < 0 && r != -ENOKEY) if (r < 0 && r != -ENOKEY)
return r; return r;
@ -117,8 +119,10 @@ static int acquire_path(void) {
"Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n" "Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n"
"Alternatively, use --path= to specify path to mount point."); "Alternatively, use --path= to specify path to mount point.");
if (esp_path) if (esp_path && xbootldr_path && !devid_set_and_equal(esp_devid, xbootldr_devid)) /* in case the two paths refer to the same inode, suppress one */
a = strv_new(esp_path, xbootldr_path); a = strv_new(esp_path, xbootldr_path);
else if (esp_path)
a = strv_new(esp_path);
else else
a = strv_new(xbootldr_path); a = strv_new(xbootldr_path);
if (!a) if (!a)
@ -130,7 +134,7 @@ static int acquire_path(void) {
_cleanup_free_ char *j = NULL; _cleanup_free_ char *j = NULL;
j = strv_join(arg_path, ":"); j = strv_join(arg_path, ":");
log_debug("Using %s as boot loader drop-in search path.", j); log_debug("Using %s as boot loader drop-in search path.", strna(j));
} }
return 0; return 0;

View File

@ -36,6 +36,7 @@
#include "rm-rf.h" #include "rm-rf.h"
#include "stat-util.h" #include "stat-util.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "string-table.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "sync-util.h" #include "sync-util.h"
@ -74,7 +75,8 @@ static int acquire_esp(
uint32_t *ret_part, uint32_t *ret_part,
uint64_t *ret_pstart, uint64_t *ret_pstart,
uint64_t *ret_psize, uint64_t *ret_psize,
sd_id128_t *ret_uuid) { sd_id128_t *ret_uuid,
dev_t *ret_devid) {
char *np; char *np;
int r; int r;
@ -85,7 +87,7 @@ static int acquire_esp(
* we simply eat up the error here, so that --list and --status work too, without noise about * we simply eat up the error here, so that --list and --status work too, without noise about
* this). */ * this). */
r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid); r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid);
if (r == -ENOKEY) { if (r == -ENOKEY) {
if (graceful) if (graceful)
return log_info_errno(r, "Couldn't find EFI system partition, skipping."); return log_info_errno(r, "Couldn't find EFI system partition, skipping.");
@ -103,16 +105,23 @@ static int acquire_esp(
return 1; return 1;
} }
static int acquire_xbootldr(bool unprivileged_mode, sd_id128_t *ret_uuid) { static int acquire_xbootldr(
bool unprivileged_mode,
sd_id128_t *ret_uuid,
dev_t *ret_devid) {
char *np; char *np;
int r; int r;
r = find_xbootldr_and_warn(arg_xbootldr_path, unprivileged_mode, &np, ret_uuid); r = find_xbootldr_and_warn(arg_xbootldr_path, unprivileged_mode, &np, ret_uuid, ret_devid);
if (r == -ENOKEY) { if (r == -ENOKEY) {
log_debug_errno(r, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT."); log_debug_errno(r, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
arg_xbootldr_path = mfree(arg_xbootldr_path);
if (ret_uuid) if (ret_uuid)
*ret_uuid = SD_ID128_NULL; *ret_uuid = SD_ID128_NULL;
arg_xbootldr_path = mfree(arg_xbootldr_path); if (ret_devid)
*ret_devid = 0;
return 0; return 0;
} }
if (r < 0) if (r < 0)
@ -411,7 +420,21 @@ static void boot_entry_file_list(const char *field, const char *root, const char
*ret_status = status; *ret_status = status;
} }
static int boot_entry_show(const BootEntry *e, bool show_as_default) { static const char* const boot_entry_type_table[_BOOT_ENTRY_TYPE_MAX] = {
[BOOT_ENTRY_CONF] = "Boot Loader Specification Type #1 (.conf)",
[BOOT_ENTRY_UNIFIED] = "Boot Loader Specification Type #2 (.efi)",
[BOOT_ENTRY_LOADER] = "Reported by Boot Loader",
[BOOT_ENTRY_LOADER_AUTO] = "Automatic",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_type, BootEntryType);
static int boot_entry_show(
const BootEntry *e,
bool show_as_default,
bool show_as_selected,
bool show_reported) {
int status = 0; int status = 0;
/* Returns 0 on success, negative on processing error, and positive if something is wrong with the /* Returns 0 on success, negative on processing error, and positive if something is wrong with the
@ -419,9 +442,30 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
assert(e); assert(e);
printf(" title: %s%s%s" "%s%s%s\n", printf(" type: %s\n",
ansi_highlight(), boot_entry_title(e), ansi_normal(), boot_entry_type_to_string(e->type));
ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal());
printf(" title: %s%s%s",
ansi_highlight(), boot_entry_title(e), ansi_normal());
if (show_as_default)
printf(" %s(default)%s",
ansi_highlight_green(), ansi_normal());
if (show_as_selected)
printf(" %s(selected)%s",
ansi_highlight_magenta(), ansi_normal());
if (show_reported) {
if (e->type == BOOT_ENTRY_LOADER)
printf(" %s(reported/absent)%s",
ansi_highlight_red(), ansi_normal());
else if (!e->reported_by_loader && e->type != BOOT_ENTRY_LOADER_AUTO)
printf(" %s(not reported/new)%s",
ansi_highlight_green(), ansi_normal());
}
putchar('\n');
if (e->id) if (e->id)
printf(" id: %s\n", e->id); printf(" id: %s\n", e->id);
@ -450,6 +494,7 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
e->root, e->root,
*s, *s,
&status); &status);
if (!strv_isempty(e->options)) { if (!strv_isempty(e->options)) {
_cleanup_free_ char *t = NULL, *t2 = NULL; _cleanup_free_ char *t = NULL, *t2 = NULL;
_cleanup_strv_free_ char **ts = NULL; _cleanup_strv_free_ char **ts = NULL;
@ -468,9 +513,16 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
printf(" options: %s\n", t2); printf(" options: %s\n", t2);
} }
if (e->device_tree) if (e->device_tree)
boot_entry_file_list("devicetree", e->root, e->device_tree, &status); boot_entry_file_list("devicetree", e->root, e->device_tree, &status);
STRV_FOREACH(s, e->device_tree_overlay)
boot_entry_file_list(s == e->device_tree_overlay ? "devicetree-overlay" : NULL,
e->root,
*s,
&status);
return -status; return -status;
} }
@ -511,7 +563,11 @@ static int status_entries(
else { else {
printf("Default Boot Loader Entry:\n"); printf("Default Boot Loader Entry:\n");
r = boot_entry_show(config.entries + config.default_entry, false); r = boot_entry_show(
config.entries + config.default_entry,
/* show_as_default= */ false,
/* show_as_selected= */ false,
/* show_discovered= */ false);
if (r > 0) if (r > 0)
/* < 0 is already logged by the function itself, let's just emit an extra warning if /* < 0 is already logged by the function itself, let's just emit an extra warning if
the default entry is broken */ the default entry is broken */
@ -1388,7 +1444,7 @@ static void print_yes_no_line(bool first, bool good, const char *name) {
static int are_we_installed(void) { static int are_we_installed(void) {
int r; int r;
r = acquire_esp(/* privileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, NULL); r = acquire_esp(/* privileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, NULL, NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -1420,9 +1476,10 @@ static int are_we_installed(void) {
static int verb_status(int argc, char *argv[], void *userdata) { static int verb_status(int argc, char *argv[], void *userdata) {
sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL; sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
dev_t esp_devid = 0, xbootldr_devid = 0;
int r, k; int r, k;
r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, &esp_uuid); r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, &esp_uuid, &esp_devid);
if (arg_print_esp_path) { if (arg_print_esp_path) {
if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
* error the find_esp_and_warn() won't log on its own) */ * error the find_esp_and_warn() won't log on its own) */
@ -1433,7 +1490,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
puts(arg_esp_path); puts(arg_esp_path);
} }
r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid); r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, &xbootldr_uuid, &xbootldr_devid);
if (arg_print_dollar_boot_path) { if (arg_print_dollar_boot_path) {
if (r == -EACCES) if (r == -EACCES)
return log_error_errno(r, "Failed to determine XBOOTLDR location: %m"); return log_error_errno(r, "Failed to determine XBOOTLDR location: %m");
@ -1567,7 +1624,14 @@ static int verb_status(int argc, char *argv[], void *userdata) {
} }
if (arg_esp_path || arg_xbootldr_path) { if (arg_esp_path || arg_xbootldr_path) {
k = status_entries(arg_esp_path, esp_uuid, arg_xbootldr_path, xbootldr_uuid); /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would find the same entries twice */
bool same = arg_esp_path && arg_xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid);
k = status_entries(
arg_esp_path,
esp_uuid,
same ? NULL : arg_xbootldr_path,
same ? SD_ID128_NULL : xbootldr_uuid);
if (k < 0) if (k < 0)
r = k; r = k;
} }
@ -1578,25 +1642,29 @@ static int verb_status(int argc, char *argv[], void *userdata) {
static int verb_list(int argc, char *argv[], void *userdata) { static int verb_list(int argc, char *argv[], void *userdata) {
_cleanup_(boot_config_free) BootConfig config = {}; _cleanup_(boot_config_free) BootConfig config = {};
_cleanup_strv_free_ char **efi_entries = NULL; _cleanup_strv_free_ char **efi_entries = NULL;
dev_t esp_devid = 0, xbootldr_devid = 0;
int r; int r;
/* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
* off logging about access errors and turn off potentially privileged device probing. Here we're interested in * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
* the latter but not the former, hence request the mode, and log about EACCES. */ * the latter but not the former, hence request the mode, and log about EACCES. */
r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL); r = acquire_esp(/* unprivileged_mode= */ geteuid() != 0, /* graceful= */ false, NULL, NULL, NULL, NULL, &esp_devid);
if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */ if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
return log_error_errno(r, "Failed to determine ESP: %m"); return log_error_errno(r, "Failed to determine ESP: %m");
if (r < 0) if (r < 0)
return r; return r;
r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL); r = acquire_xbootldr(/* unprivileged_mode= */ geteuid() != 0, NULL, &xbootldr_devid);
if (r == -EACCES) if (r == -EACCES)
return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m"); return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
if (r < 0) if (r < 0)
return r; return r;
r = boot_entries_load_config(arg_esp_path, arg_xbootldr_path, &config); /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would find the same entries twice */
bool same = arg_esp_path && arg_xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid);
r = boot_entries_load_config(arg_esp_path, same ? NULL : arg_xbootldr_path, &config);
if (r < 0) if (r < 0)
return r; return r;
@ -1606,7 +1674,7 @@ static int verb_list(int argc, char *argv[], void *userdata) {
else if (r < 0) else if (r < 0)
log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m"); log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m");
else else
(void) boot_entries_augment_from_loader(&config, efi_entries); (void) boot_entries_augment_from_loader(&config, efi_entries, /* only_auto= */ false);
if (config.n_entries == 0) if (config.n_entries == 0)
log_info("No boot loader entries found."); log_info("No boot loader entries found.");
@ -1616,7 +1684,11 @@ static int verb_list(int argc, char *argv[], void *userdata) {
printf("Boot Loader Entries:\n"); printf("Boot Loader Entries:\n");
for (size_t n = 0; n < config.n_entries; n++) { for (size_t n = 0; n < config.n_entries; n++) {
r = boot_entry_show(config.entries + n, n == (size_t) config.default_entry); r = boot_entry_show(
config.entries + n,
/* show_as_default= */ n == (size_t) config.default_entry,
/* show_as_selected= */ n == (size_t) config.selected_entry,
/* show_discovered= */ true);
if (r < 0) if (r < 0)
return r; return r;
@ -1788,7 +1860,7 @@ static int verb_install(int argc, char *argv[], void *userdata) {
install = streq(argv[0], "install"); install = streq(argv[0], "install");
graceful = !install && arg_graceful; /* support graceful mode for updates */ graceful = !install && arg_graceful; /* support graceful mode for updates */
r = acquire_esp(/* unprivileged_mode= */ false, graceful, &part, &pstart, &psize, &uuid); r = acquire_esp(/* unprivileged_mode= */ false, graceful, &part, &pstart, &psize, &uuid, NULL);
if (graceful && r == -ENOKEY) if (graceful && r == -ENOKEY)
return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */ return 0; /* If --graceful is specified and we can't find an ESP, handle this cleanly */
if (r < 0) if (r < 0)
@ -1805,7 +1877,7 @@ static int verb_install(int argc, char *argv[], void *userdata) {
} }
} }
r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL); r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL, NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -1865,11 +1937,11 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
sd_id128_t uuid = SD_ID128_NULL; sd_id128_t uuid = SD_ID128_NULL;
int r, q; int r, q;
r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, &uuid); r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false, NULL, NULL, NULL, &uuid, NULL);
if (r < 0) if (r < 0)
return r; return r;
r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL); r = acquire_xbootldr(/* unprivileged_mode= */ false, NULL, NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -2078,7 +2150,7 @@ static int verb_set_efivar(int argc, char *argv[], void *userdata) {
static int verb_random_seed(int argc, char *argv[], void *userdata) { static int verb_random_seed(int argc, char *argv[], void *userdata) {
int r; int r;
r = find_esp_and_warn(arg_esp_path, false, &arg_esp_path, NULL, NULL, NULL, NULL); r = find_esp_and_warn(arg_esp_path, false, &arg_esp_path, NULL, NULL, NULL, NULL, NULL);
if (r == -ENOKEY) { if (r == -ENOKEY) {
/* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */ /* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */
if (!arg_graceful) if (!arg_graceful)

View File

@ -13,6 +13,7 @@
#include "hashmap.h" #include "hashmap.h"
#include "macro.h" #include "macro.h"
#include "memory-util.h" #include "memory-util.h"
#include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "time-util.h" #include "time-util.h"
#include "user-util.h" #include "user-util.h"
@ -167,9 +168,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
if (!S_ISREG(st.st_mode)) if (!S_ISREG(st.st_mode))
continue; continue;
if (exclude_fd >= 0 && if (exclude_fd >= 0 && stat_inode_same(&exclude_st, &st))
exclude_st.st_dev == st.st_dev &&
exclude_st.st_ino == st.st_ino)
continue; continue;
r = hashmap_ensure_allocated(&h, NULL); r = hashmap_ensure_allocated(&h, NULL);

View File

@ -721,7 +721,7 @@ static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) {
return -errno; return -errno;
/* The process uses system root. */ /* The process uses system root. */
if (proc_root_stat.st_ino == root_stat.st_ino) { if (stat_inode_same(&proc_root_stat, &root_stat)) {
*cmdline = NULL; *cmdline = NULL;
return 0; return 0;
} }

View File

@ -779,12 +779,16 @@ static int add_mounts(void) {
return btrfs_log_dev_root(LOG_ERR, r, "root file system"); return btrfs_log_dev_root(LOG_ERR, r, "root file system");
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to determine block device of root file system: %m"); return log_error_errno(r, "Failed to determine block device of root file system: %m");
if (r == 0) { /* Not backed by block device */ if (r == 0) { /* Not backed by a single block device. (Could be NFS or so, or could be multi-device RAID or so) */
r = get_block_device_harder("/usr", &devno); r = get_block_device_harder("/usr", &devno);
if (r == -EUCLEAN) if (r == -EUCLEAN)
return btrfs_log_dev_root(LOG_ERR, r, "/usr"); return btrfs_log_dev_root(LOG_ERR, r, "/usr");
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to determine block device of /usr file system: %m"); return log_error_errno(r, "Failed to determine block device of /usr/ file system: %m");
if (r == 0) { /* /usr/ not backed by single block device, either. */
log_debug("Neither root nor /usr/ file system are on a (single) block device.");
return 0;
}
} }
} else if (r < 0) } else if (r < 0)
return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m"); return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");

View File

@ -1239,10 +1239,7 @@ static int manager_add_device(Manager *m, sd_device *d) {
return 0; return 0;
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to acquire ID_PART_ENTRY_TYPE device property, ignoring: %m"); return log_error_errno(r, "Failed to acquire ID_PART_ENTRY_TYPE device property, ignoring: %m");
r = sd_id128_from_string(parttype, &id); if (id128_equal_string(parttype, GPT_USER_HOME) <= 0) {
if (r < 0)
return log_debug_errno(r, "Failed to parse ID_PART_ENTRY_TYPE field '%s', ignoring: %m", parttype);
if (!sd_id128_equal(id, GPT_USER_HOME)) {
log_debug("Found partition (%s) we don't care about, ignoring.", sysfs); log_debug("Found partition (%s) we don't care about, ignoring.", sysfs);
return 0; return 0;
} }

View File

@ -28,6 +28,7 @@
#include "filesystems.h" #include "filesystems.h"
#include "fs-util.h" #include "fs-util.h"
#include "fsck-util.h" #include "fsck-util.h"
#include "gpt.h"
#include "home-util.h" #include "home-util.h"
#include "homework-luks.h" #include "homework-luks.h"
#include "homework-mount.h" #include "homework-mount.h"
@ -703,7 +704,7 @@ static int luks_validate(
if (!pp) if (!pp)
return errno > 0 ? -errno : -EIO; return errno > 0 ? -errno : -EIO;
if (!streq_ptr(blkid_partition_get_type_string(pp), "773f91ef-66d4-49b5-bd83-d683bf40ad16")) if (id128_equal_string(blkid_partition_get_type_string(pp), GPT_USER_HOME) <= 0)
continue; continue;
if (!streq_ptr(blkid_partition_get_name(pp), label)) if (!streq_ptr(blkid_partition_get_name(pp), label))
@ -1762,7 +1763,7 @@ static int luks_format(
CRYPT_LUKS2, CRYPT_LUKS2,
user_record_luks_cipher(hr), user_record_luks_cipher(hr),
user_record_luks_cipher_mode(hr), user_record_luks_cipher_mode(hr),
ID128_TO_UUID_STRING(uuid), SD_ID128_TO_UUID_STRING(uuid),
volume_key, volume_key,
volume_key_size, volume_key_size,
&(struct crypt_params_luks2) { &(struct crypt_params_luks2) {
@ -1858,7 +1859,7 @@ static int make_partition_table(
if (!t) if (!t)
return log_oom(); return log_oom();
r = fdisk_parttype_set_typestr(t, "773f91ef-66d4-49b5-bd83-d683bf40ad16"); r = fdisk_parttype_set_typestr(t, SD_ID128_TO_UUID_STRING(GPT_USER_HOME));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to initialize partition type: %m"); return log_error_errno(r, "Failed to initialize partition type: %m");
@ -1917,7 +1918,7 @@ static int make_partition_table(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set partition name: %m"); return log_error_errno(r, "Failed to set partition name: %m");
r = fdisk_partition_set_uuid(p, ID128_TO_UUID_STRING(uuid)); r = fdisk_partition_set_uuid(p, SD_ID128_TO_UUID_STRING(uuid));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set partition UUID: %m"); return log_error_errno(r, "Failed to set partition UUID: %m");
@ -2745,7 +2746,7 @@ static int ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *userdata
if (!result) if (!result)
return log_oom(); return log_oom();
fdisk_ask_string_set_result(ask, id128_to_uuid_string(*(sd_id128_t*) userdata, result)); fdisk_ask_string_set_result(ask, sd_id128_to_uuid_string(*(sd_id128_t*) userdata, result));
break; break;
default: default:

View File

@ -332,9 +332,9 @@ int user_record_add_binding(
r = json_build(&new_binding_entry, r = json_build(&new_binding_entry,
JSON_BUILD_OBJECT( JSON_BUILD_OBJECT(
JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)), JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)),
JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(partition_uuid), "partitionUuid", JSON_BUILD_STRING(ID128_TO_UUID_STRING(partition_uuid))), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(partition_uuid), "partitionUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(partition_uuid))),
JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(ID128_TO_UUID_STRING(luks_uuid))), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(luks_uuid), "luksUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(luks_uuid))),
JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(fs_uuid), "fileSystemUuid", JSON_BUILD_STRING(ID128_TO_UUID_STRING(fs_uuid))), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(fs_uuid), "fileSystemUuid", JSON_BUILD_STRING(SD_ID128_TO_UUID_STRING(fs_uuid))),
JSON_BUILD_PAIR_CONDITION(!!luks_cipher, "luksCipher", JSON_BUILD_STRING(luks_cipher)), JSON_BUILD_PAIR_CONDITION(!!luks_cipher, "luksCipher", JSON_BUILD_STRING(luks_cipher)),
JSON_BUILD_PAIR_CONDITION(!!luks_cipher_mode, "luksCipherMode", JSON_BUILD_STRING(luks_cipher_mode)), JSON_BUILD_PAIR_CONDITION(!!luks_cipher_mode, "luksCipherMode", JSON_BUILD_STRING(luks_cipher_mode)),
JSON_BUILD_PAIR_CONDITION(luks_volume_key_size != UINT64_MAX, "luksVolumeKeySize", JSON_BUILD_UNSIGNED(luks_volume_key_size)), JSON_BUILD_PAIR_CONDITION(luks_volume_key_size != UINT64_MAX, "luksVolumeKeySize", JSON_BUILD_UNSIGNED(luks_volume_key_size)),

View File

@ -769,3 +769,8 @@ global:
sd_event_add_inotify_fd; sd_event_add_inotify_fd;
sd_event_source_set_ratelimit_expire_callback; sd_event_source_set_ratelimit_expire_callback;
} LIBSYSTEMD_249; } LIBSYSTEMD_249;
LIBSYSTEMD_251 {
global:
sd_id128_to_uuid_string;
} LIBSYSTEMD_250;

View File

@ -23,6 +23,7 @@
#include "path-util.h" #include "path-util.h"
#include "process-util.h" #include "process-util.h"
#include "socket-util.h" #include "socket-util.h"
#include "stat-util.h"
#include "strv.h" #include "strv.h"
#include "time-util.h" #include "time-util.h"
#include "util.h" #include "util.h"
@ -150,9 +151,7 @@ _public_ int sd_is_fifo(int fd, const char *path) {
return -errno; return -errno;
} }
return return stat_inode_same(&st_path, &st_fd);
st_path.st_dev == st_fd.st_dev &&
st_path.st_ino == st_fd.st_ino;
} }
return 1; return 1;
@ -181,9 +180,7 @@ _public_ int sd_is_special(int fd, const char *path) {
} }
if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
return return stat_inode_same(&st_path, &st_fd);
st_path.st_dev == st_fd.st_dev &&
st_path.st_ino == st_fd.st_ino;
else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
return st_path.st_rdev == st_fd.st_rdev; return st_path.st_rdev == st_fd.st_rdev;
else else
@ -415,7 +412,7 @@ _public_ int sd_is_mq(int fd, const char *path) {
} }
if (path) { if (path) {
char fpath[PATH_MAX]; _cleanup_free_ char *fpath = NULL;
struct stat a, b; struct stat a, b;
assert_return(path_is_absolute(path), -EINVAL); assert_return(path_is_absolute(path), -EINVAL);
@ -423,14 +420,14 @@ _public_ int sd_is_mq(int fd, const char *path) {
if (fstat(fd, &a) < 0) if (fstat(fd, &a) < 0)
return -errno; return -errno;
strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); fpath = path_join("/dev/mqueue", path);
fpath[sizeof(fpath)-1] = 0; if (!fpath)
return -ENOMEM;
if (stat(fpath, &b) < 0) if (stat(fpath, &b) < 0)
return -errno; return -errno;
if (a.st_dev != b.st_dev || if (!stat_inode_same(&a, &b))
a.st_ino != b.st_ino)
return 0; return 0;
} }

View File

@ -24,6 +24,7 @@
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "set.h" #include "set.h"
#include "socket-util.h" #include "socket-util.h"
#include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
@ -195,7 +196,7 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
else else
log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns, ignoring: %m"); log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns, ignoring: %m");
} else if (a.st_dev != b.st_dev || a.st_ino != b.st_ino) } else if (!stat_inode_same(&a, &b))
log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events."); log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events.");
} }
} }

View File

@ -248,6 +248,10 @@ _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum)
assert_return(ret, -EINVAL); assert_return(ret, -EINVAL);
assert_return(IN_SET(type, 'b', 'c'), -EINVAL); assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
if (devnum == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
"sd-device: Attempted to allocate device by zero major/minor, refusing.");
/* use /sys/dev/{block,char}/<maj>:<min> link */ /* use /sys/dev/{block,char}/<maj>:<min> link */
xsprintf(id, "%u:%u", major(devnum), minor(devnum)); xsprintf(id, "%u:%u", major(devnum), minor(devnum));
@ -2194,7 +2198,7 @@ _public_ int sd_device_trigger_with_uuid(
if (r < 0) if (r < 0)
return r; return r;
j = strjoina(s, " ", ID128_TO_UUID_STRING(u)); j = strjoina(s, " ", SD_ID128_TO_UUID_STRING(u));
r = sd_device_set_sysattr_value(device, "uevent", j); r = sd_device_set_sysattr_value(device, "uevent", j);
if (r < 0) if (r < 0)

View File

@ -10,6 +10,7 @@
#include "device-private.h" #include "device-private.h"
#include "device-util.h" #include "device-util.h"
#include "macro.h" #include "macro.h"
#include "stat-util.h"
#include "string-util.h" #include "string-util.h"
#include "tests.h" #include "tests.h"
#include "util.h" #include "util.h"
@ -24,11 +25,10 @@ static int monitor_handler(sd_device_monitor *m, sd_device *d, void *userdata) {
return sd_event_exit(sd_device_monitor_get_event(m), 100); return sd_event_exit(sd_device_monitor_get_event(m), 100);
} }
static int test_receive_device_fail(void) { static void test_receive_device_fail(void) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor_server = NULL, *monitor_client = NULL;
_cleanup_(sd_device_unrefp) sd_device *loopback = NULL; _cleanup_(sd_device_unrefp) sd_device *loopback = NULL;
const char *syspath; const char *syspath;
int r;
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
@ -47,14 +47,8 @@ static int test_receive_device_fail(void) {
assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0); assert_se(sd_device_monitor_start(monitor_client, monitor_handler, (void *) syspath) >= 0);
assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0); assert_se(sd_event_source_set_description(sd_device_monitor_get_event_source(monitor_client), "receiver") >= 0);
/* Do not use assert_se() here. */ assert_se(device_monitor_send_device(monitor_server, monitor_client, loopback) >= 0);
r = device_monitor_send_device(monitor_server, monitor_client, loopback);
if (r < 0)
return log_error_errno(r, "Failed to send loopback device: %m");
assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0); assert_se(sd_event_run(sd_device_monitor_get_event(monitor_client), 0) >= 0);
return 0;
} }
static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool tag_filter, bool use_bpf) { static void test_send_receive_one(sd_device *device, bool subsystem_filter, bool tag_filter, bool use_bpf) {
@ -299,11 +293,10 @@ int main(int argc, char *argv[]) {
if (getuid() != 0) if (getuid() != 0)
return log_tests_skipped("not root"); return log_tests_skipped("not root");
r = test_receive_device_fail(); if (path_is_read_only_fs("/sys") > 0)
if (r < 0) {
assert_se(r == -EPERM && detect_container() > 0);
return log_tests_skipped("Running in container"); return log_tests_skipped("Running in container");
}
test_receive_device_fail();
assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0); assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0);
assert_se(device_add_property(loopback, "ACTION", "add") >= 0); assert_se(device_add_property(loopback, "ACTION", "add") >= 0);

View File

@ -12,29 +12,6 @@
#include "string-util.h" #include "string-util.h"
#include "sync-util.h" #include "sync-util.h"
char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) {
unsigned n, k = 0;
assert(s);
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
for (n = 0; n < 16; n++) {
if (IN_SET(n, 4, 6, 8, 10))
s[k++] = '-';
s[k++] = hexchar(id.bytes[n] >> 4);
s[k++] = hexchar(id.bytes[n] & 0xF);
}
assert(k == 36);
s[k] = 0;
return s;
}
bool id128_is_valid(const char *s) { bool id128_is_valid(const char *s) {
size_t i, l; size_t i, l;
@ -153,13 +130,13 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
assert(f < _ID128_FORMAT_MAX); assert(f < _ID128_FORMAT_MAX);
if (f != ID128_UUID) { if (f != ID128_UUID) {
sd_id128_to_string(id, buffer); assert_se(sd_id128_to_string(id, buffer));
buffer[32] = '\n'; buffer[SD_ID128_STRING_MAX - 1] = '\n';
sz = 33; sz = SD_ID128_STRING_MAX;
} else { } else {
id128_to_uuid_string(id, buffer); assert_se(sd_id128_to_uuid_string(id, buffer));
buffer[36] = '\n'; buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
sz = 37; sz = SD_ID128_UUID_STRING_MAX;
} }
r = loop_write(fd, buffer, sz, false); r = loop_write(fd, buffer, sz, false);
@ -229,3 +206,19 @@ int id128_get_product(sd_id128_t *ret) {
*ret = uuid; *ret = uuid;
return 0; return 0;
} }
int id128_equal_string(const char *s, sd_id128_t id) {
sd_id128_t parsed;
int r;
if (!s)
return false;
/* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */
r = sd_id128_from_string(s, &parsed);
if (r < 0)
return r;
return sd_id128_equal(parsed, id);
}

View File

@ -8,12 +8,6 @@
#include "hash-funcs.h" #include "hash-funcs.h"
#include "macro.h" #include "macro.h"
#define ID128_UUID_STRING_MAX 37
char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]);
#define ID128_TO_UUID_STRING(id) id128_to_uuid_string((id), (char[ID128_UUID_STRING_MAX]) {})
bool id128_is_valid(const char *s) _pure_; bool id128_is_valid(const char *s) _pure_;
typedef enum Id128Format { typedef enum Id128Format {
@ -40,3 +34,5 @@ extern const struct hash_ops id128_hash_ops;
sd_id128_t id128_make_v4_uuid(sd_id128_t id); sd_id128_t id128_make_v4_uuid(sd_id128_t id);
int id128_get_product(sd_id128_t *ret); int id128_get_product(sd_id128_t *ret);
int id128_equal_string(const char *s, sd_id128_t id);

View File

@ -19,16 +19,36 @@
#include "util.h" #include "util.h"
_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) { _public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) {
unsigned n;
assert_return(s, NULL); assert_return(s, NULL);
for (n = 0; n < 16; n++) { for (size_t n = 0; n < 16; n++) {
s[n*2] = hexchar(id.bytes[n] >> 4); s[n*2] = hexchar(id.bytes[n] >> 4);
s[n*2+1] = hexchar(id.bytes[n] & 0xF); s[n*2+1] = hexchar(id.bytes[n] & 0xF);
} }
s[32] = 0; s[SD_ID128_STRING_MAX-1] = 0;
return s;
}
_public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_UUID_STRING_MAX]) {
size_t k = 0;
assert_return(s, NULL);
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
for (size_t n = 0; n < 16; n++) {
if (IN_SET(n, 4, 6, 8, 10))
s[k++] = '-';
s[k++] = hexchar(id.bytes[n] >> 4);
s[k++] = hexchar(id.bytes[n] & 0xF);
}
assert(k == SD_ID128_UUID_STRING_MAX - 1);
s[k] = 0;
return s; return s;
} }

View File

@ -1317,8 +1317,7 @@ static int add_any_file(
f = ordered_hashmap_get(j->files, path); f = ordered_hashmap_get(j->files, path);
if (f) { if (f) {
if (f->last_stat.st_dev == st.st_dev && if (stat_inode_same(&f->last_stat, &st)) {
f->last_stat.st_ino == st.st_ino) {
/* We already track this file, under the same path and with the same device/inode numbers, it's /* We already track this file, under the same path and with the same device/inode numbers, it's
* hence really the same. Mark this file as seen in this generation. This is used to GC old * hence really the same. Mark this file as seen in this generation. This is used to GC old

View File

@ -20,101 +20,99 @@
static const ActionTableItem action_table[_HANDLE_ACTION_MAX] = { static const ActionTableItem action_table[_HANDLE_ACTION_MAX] = {
[HANDLE_POWEROFF] = { [HANDLE_POWEROFF] = {
SPECIAL_POWEROFF_TARGET, .handle = HANDLE_POWEROFF,
INHIBIT_SHUTDOWN, .target = SPECIAL_POWEROFF_TARGET,
"org.freedesktop.login1.power-off", .inhibit_what = INHIBIT_SHUTDOWN,
"org.freedesktop.login1.power-off-multiple-sessions", .polkit_action = "org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions",
_SLEEP_OPERATION_INVALID, .polkit_action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit",
SD_MESSAGE_SHUTDOWN_STR, .sleep_operation = _SLEEP_OPERATION_INVALID,
"System is powering down", .message_id = SD_MESSAGE_SHUTDOWN_STR,
"power-off", .message = "System is powering down",
.log_message = "power-off",
}, },
[HANDLE_REBOOT] = { [HANDLE_REBOOT] = {
SPECIAL_REBOOT_TARGET, .handle = HANDLE_REBOOT,
INHIBIT_SHUTDOWN, .target = SPECIAL_REBOOT_TARGET,
"org.freedesktop.login1.reboot", .inhibit_what = INHIBIT_SHUTDOWN,
"org.freedesktop.login1.reboot-multiple-sessions", .polkit_action = "org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions",
_SLEEP_OPERATION_INVALID, .polkit_action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit",
SD_MESSAGE_SHUTDOWN_STR, .sleep_operation = _SLEEP_OPERATION_INVALID,
"System is rebooting", .message_id = SD_MESSAGE_SHUTDOWN_STR,
"reboot", .message = "System is rebooting",
.log_message = "reboot",
}, },
[HANDLE_HALT] = { [HANDLE_HALT] = {
SPECIAL_HALT_TARGET, .handle = HANDLE_HALT,
INHIBIT_SHUTDOWN, .target = SPECIAL_HALT_TARGET,
"org.freedesktop.login1.halt", .inhibit_what = INHIBIT_SHUTDOWN,
"org.freedesktop.login1.halt-multiple-sessions", .polkit_action = "org.freedesktop.login1.halt",
"org.freedesktop.login1.halt-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions",
_SLEEP_OPERATION_INVALID, .polkit_action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit",
SD_MESSAGE_SHUTDOWN_STR, .sleep_operation = _SLEEP_OPERATION_INVALID,
"System is halting", .message_id = SD_MESSAGE_SHUTDOWN_STR,
"halt", .message = "System is halting",
.log_message = "halt",
}, },
[HANDLE_KEXEC] = { [HANDLE_KEXEC] = {
SPECIAL_KEXEC_TARGET, .handle = HANDLE_KEXEC,
INHIBIT_SHUTDOWN, .target = SPECIAL_KEXEC_TARGET,
"org.freedesktop.login1.reboot", .inhibit_what = INHIBIT_SHUTDOWN,
"org.freedesktop.login1.reboot-multiple-sessions", .polkit_action = "org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions",
_SLEEP_OPERATION_INVALID, .polkit_action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit",
SD_MESSAGE_SHUTDOWN_STR, .sleep_operation = _SLEEP_OPERATION_INVALID,
"System is rebooting with kexec", .message_id = SD_MESSAGE_SHUTDOWN_STR,
"kexec", .message = "System is rebooting with kexec",
.log_message = "kexec",
}, },
[HANDLE_SUSPEND] = { [HANDLE_SUSPEND] = {
SPECIAL_SUSPEND_TARGET, .handle = HANDLE_SUSPEND,
INHIBIT_SLEEP, .target = SPECIAL_SUSPEND_TARGET,
"org.freedesktop.login1.suspend", .inhibit_what = INHIBIT_SLEEP,
"org.freedesktop.login1.suspend-multiple-sessions", .polkit_action = "org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.suspend-multiple-sessions",
SLEEP_SUSPEND, .polkit_action_ignore_inhibit = "org.freedesktop.login1.suspend-ignore-inhibit",
.sleep_operation = SLEEP_SUSPEND,
}, },
[HANDLE_HIBERNATE] = { [HANDLE_HIBERNATE] = {
SPECIAL_HIBERNATE_TARGET, .handle = HANDLE_HIBERNATE,
INHIBIT_SLEEP, .target = SPECIAL_HIBERNATE_TARGET,
"org.freedesktop.login1.hibernate", .inhibit_what = INHIBIT_SLEEP,
"org.freedesktop.login1.hibernate-multiple-sessions", .polkit_action = "org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.hibernate-multiple-sessions",
SLEEP_HIBERNATE, .polkit_action_ignore_inhibit = "org.freedesktop.login1.hibernate-ignore-inhibit",
.sleep_operation = SLEEP_HIBERNATE,
}, },
[HANDLE_HYBRID_SLEEP] = { [HANDLE_HYBRID_SLEEP] = {
SPECIAL_HYBRID_SLEEP_TARGET, .handle = HANDLE_HYBRID_SLEEP,
INHIBIT_SLEEP, .target = SPECIAL_HYBRID_SLEEP_TARGET,
"org.freedesktop.login1.hibernate", .inhibit_what = INHIBIT_SLEEP,
"org.freedesktop.login1.hibernate-multiple-sessions", .polkit_action = "org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.hibernate-multiple-sessions",
SLEEP_HYBRID_SLEEP, .polkit_action_ignore_inhibit = "org.freedesktop.login1.hibernate-ignore-inhibit",
.sleep_operation = SLEEP_HYBRID_SLEEP,
}, },
[HANDLE_SUSPEND_THEN_HIBERNATE] = { [HANDLE_SUSPEND_THEN_HIBERNATE] = {
SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, .handle = HANDLE_SUSPEND_THEN_HIBERNATE,
INHIBIT_SLEEP, .target = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
"org.freedesktop.login1.hibernate", .inhibit_what = INHIBIT_SLEEP,
"org.freedesktop.login1.hibernate-multiple-sessions", .polkit_action = "org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-ignore-inhibit", .polkit_action_multiple_sessions = "org.freedesktop.login1.hibernate-multiple-sessions",
SLEEP_SUSPEND_THEN_HIBERNATE, .polkit_action_ignore_inhibit = "org.freedesktop.login1.hibernate-ignore-inhibit",
.sleep_operation = SLEEP_SUSPEND_THEN_HIBERNATE,
}, },
[HANDLE_FACTORY_RESET] = { [HANDLE_FACTORY_RESET] = {
SPECIAL_FACTORY_RESET_TARGET, .handle = HANDLE_FACTORY_RESET,
_INHIBIT_WHAT_INVALID, .target = SPECIAL_FACTORY_RESET_TARGET,
NULL, .inhibit_what = _INHIBIT_WHAT_INVALID,
NULL, .sleep_operation = _SLEEP_OPERATION_INVALID,
NULL, .message_id = SD_MESSAGE_FACTORY_RESET_STR,
_SLEEP_OPERATION_INVALID, .message = "System is performing factory reset",
SD_MESSAGE_FACTORY_RESET_STR,
"System is performing factory reset",
NULL
}, },
}; };
const char* manager_target_for_action(HandleAction handle) {
assert(handle >= 0);
assert(handle < (ssize_t) ELEMENTSOF(action_table));
return action_table[handle].target;
}
const ActionTableItem* manager_item_for_handle(HandleAction handle) { const ActionTableItem* manager_item_for_handle(HandleAction handle) {
assert(handle >= 0); assert(handle >= 0);
assert(handle < (ssize_t) ELEMENTSOF(action_table)); assert(handle < (ssize_t) ELEMENTSOF(action_table));
@ -122,12 +120,6 @@ const ActionTableItem* manager_item_for_handle(HandleAction handle) {
return &action_table[handle]; return &action_table[handle];
} }
HandleAction manager_handle_for_item(const ActionTableItem* a) {
if (a && a < action_table + ELEMENTSOF(action_table))
return a - action_table;
return _HANDLE_ACTION_INVALID;
}
int manager_handle_action( int manager_handle_action(
Manager *m, Manager *m,
InhibitWhat inhibit_key, InhibitWhat inhibit_key,

View File

@ -28,6 +28,7 @@ typedef struct ActionTableItem ActionTableItem;
#include "sleep-config.h" #include "sleep-config.h"
struct ActionTableItem { struct ActionTableItem {
HandleAction handle;
const char *target; const char *target;
InhibitWhat inhibit_what; InhibitWhat inhibit_what;
const char *polkit_action; const char *polkit_action;
@ -36,8 +37,7 @@ struct ActionTableItem {
SleepOperation sleep_operation; SleepOperation sleep_operation;
const char* message_id; const char* message_id;
const char* message; const char* message;
const char* log_str; const char* log_message;
}; };
int manager_handle_action( int manager_handle_action(
@ -50,7 +50,6 @@ int manager_handle_action(
const char* handle_action_to_string(HandleAction h) _const_; const char* handle_action_to_string(HandleAction h) _const_;
HandleAction handle_action_from_string(const char *s) _pure_; HandleAction handle_action_from_string(const char *s) _pure_;
const char* manager_target_for_action(HandleAction handle);
const ActionTableItem* manager_item_for_handle(HandleAction handle); const ActionTableItem* manager_item_for_handle(HandleAction handle);
HandleAction manager_handle_for_item(const ActionTableItem* a); HandleAction manager_handle_for_item(const ActionTableItem* a);

View File

@ -54,6 +54,15 @@
#include "utmp-wtmp.h" #include "utmp-wtmp.h"
#include "virt.h" #include "virt.h"
/* As a random fun fact sysvinit had a 252 (256-(strlen(" \r\n")+1))
* character limit for the wall message.
* https://git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/shutdown.c#n72
* There is no real technical need for that but doesn't make sense
* to store arbitrary amounts either. As we are not stingy here, we
* allow 4k.
*/
#define WALL_MESSAGE_MAX 4096
static void reset_scheduled_shutdown(Manager *m); static void reset_scheduled_shutdown(Manager *m);
static int get_sender_session( static int get_sender_session(
@ -349,7 +358,7 @@ static int property_get_scheduled_shutdown(
return r; return r;
r = sd_bus_message_append(reply, "st", r = sd_bus_message_append(reply, "st",
handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)), m->scheduled_shutdown_type ? handle_action_to_string(m->scheduled_shutdown_type->handle) : NULL,
m->scheduled_shutdown_timeout); m->scheduled_shutdown_timeout);
if (r < 0) if (r < 0)
return r; return r;
@ -1499,13 +1508,13 @@ static int bus_manager_log_shutdown(
Manager *m, Manager *m,
const ActionTableItem *a) { const ActionTableItem *a) {
const char *message, *log_str; const char *message, *log_message;
assert(m); assert(m);
assert(a); assert(a);
message = a->message; message = a->message;
log_str = a->log_str; log_message = a->log_message;
if (message) if (message)
message = strjoina("MESSAGE=", message); message = strjoina("MESSAGE=", message);
@ -1517,13 +1526,13 @@ static int bus_manager_log_shutdown(
else else
message = strjoina(message, " (", m->wall_message, ")."); message = strjoina(message, " (", m->wall_message, ").");
if (log_str) if (log_message)
log_str = strjoina("SHUTDOWN=", log_str); log_message = strjoina("SHUTDOWN=", log_message);
return log_struct(LOG_NOTICE, return log_struct(LOG_NOTICE,
"MESSAGE_ID=%s", a->message_id ? a->message_id : SD_MESSAGE_SHUTDOWN_STR, "MESSAGE_ID=%s", a->message_id ? a->message_id : SD_MESSAGE_SHUTDOWN_STR,
message, message,
log_str); log_message);
} }
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) { static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
@ -1884,7 +1893,7 @@ static int method_do_shutdown_or_sleep(
return r; return r;
if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0) if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
if (manager_handle_for_item(a) != HANDLE_REBOOT && (flags & SD_LOGIND_REBOOT_VIA_KEXEC)) if (a->handle != HANDLE_REBOOT && (flags & SD_LOGIND_REBOOT_VIA_KEXEC))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec is only applicable with reboot operations"); return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec is only applicable with reboot operations");
} else { } else {
/* Old style method: no flags parameter, but interactive bool passed as boolean in /* Old style method: no flags parameter, but interactive bool passed as boolean in
@ -2035,6 +2044,7 @@ static int update_schedule_file(Manager *m) {
int r; int r;
assert(m); assert(m);
assert(m->scheduled_shutdown_type);
r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0, MKDIR_WARN_MODE); r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0, MKDIR_WARN_MODE);
if (r < 0) if (r < 0)
@ -2052,7 +2062,7 @@ static int update_schedule_file(Manager *m) {
"MODE=%s\n", "MODE=%s\n",
m->scheduled_shutdown_timeout, m->scheduled_shutdown_timeout,
m->enable_wall_messages, m->enable_wall_messages,
handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type))); handle_action_to_string(m->scheduled_shutdown_type->handle));
if (!isempty(m->wall_message)) { if (!isempty(m->wall_message)) {
_cleanup_free_ char *t = NULL; _cleanup_free_ char *t = NULL;
@ -2240,9 +2250,10 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
assert(m); assert(m);
assert(message); assert(message);
cancelled = !IN_SET(manager_handle_for_item(m->scheduled_shutdown_type), HANDLE_IGNORE, _HANDLE_ACTION_INVALID); cancelled = m->scheduled_shutdown_type
&& !IN_SET(m->scheduled_shutdown_type->handle, HANDLE_IGNORE, _HANDLE_ACTION_INVALID);
if (!cancelled) if (!cancelled)
goto done; return sd_bus_reply_method_return(message, "b", false);
a = m->scheduled_shutdown_type; a = m->scheduled_shutdown_type;
if (!a->polkit_action) if (!a->polkit_action)
@ -2281,8 +2292,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
username, tty, logind_wall_tty_filter, m); username, tty, logind_wall_tty_filter, m);
} }
done: return sd_bus_reply_method_return(message, "b", true);
return sd_bus_reply_method_return(message, "b", cancelled);
} }
static int method_can_shutdown_or_sleep( static int method_can_shutdown_or_sleep(
@ -2328,7 +2338,7 @@ static int method_can_shutdown_or_sleep(
if (handle >= 0) { if (handle >= 0) {
const char *target; const char *target;
target = manager_target_for_action(handle); target = manager_item_for_handle(handle)->target;
if (target) { if (target) {
_cleanup_free_ char *load_state = NULL; _cleanup_free_ char *load_state = NULL;
@ -2923,9 +2933,9 @@ static int boot_loader_entry_exists(Manager *m, const char *id) {
r = manager_read_efi_boot_loader_entries(m); r = manager_read_efi_boot_loader_entries(m);
if (r >= 0) if (r >= 0)
(void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries); (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, /* auto_only= */ true);
return boot_config_has_entry(&config, id); return !!boot_config_find_entry(&config, id);
} }
static int method_set_reboot_to_boot_loader_entry( static int method_set_reboot_to_boot_loader_entry(
@ -3081,7 +3091,7 @@ static int property_get_boot_loader_entries(
r = manager_read_efi_boot_loader_entries(m); r = manager_read_efi_boot_loader_entries(m);
if (r >= 0) if (r >= 0)
(void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries); (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, /* auto_only= */ true);
r = sd_bus_message_open_container(reply, 'a', "s"); r = sd_bus_message_open_container(reply, 'a', "s");
if (r < 0) if (r < 0)
@ -3115,14 +3125,10 @@ static int method_set_wall_message(
if (r < 0) if (r < 0)
return r; return r;
/* sysvinit has a 252 (256-(strlen(" \r\n")+1)) character if (strlen(wall_message) > WALL_MESSAGE_MAX)
* limit for the wall message. There is no real technical return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
* need for that but doesn't make sense to store arbitrary "Wall message too long, maximum permitted length is %u characters.",
* amounts either. WALL_MESSAGE_MAX);
* https://git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/shutdown.c#n72)
*/
if (strlen(wall_message) > 252)
return -EMSGSIZE;
/* Short-circuit the operation if the desired state is already in place, to /* Short-circuit the operation if the desired state is already in place, to
* avoid an unnecessary polkit permission check. */ * avoid an unnecessary polkit permission check. */

View File

@ -64,7 +64,7 @@ static int warn_wall(Manager *m, usec_t n) {
assert(m); assert(m);
if (!m->enable_wall_messages) if (!m->enable_wall_messages || !m->scheduled_shutdown_type)
return 0; return 0;
left = m->scheduled_shutdown_timeout > n; left = m->scheduled_shutdown_timeout > n;
@ -72,7 +72,7 @@ static int warn_wall(Manager *m, usec_t n) {
r = asprintf(&l, "%s%sThe system is going down for %s %s%s!", r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
strempty(m->wall_message), strempty(m->wall_message),
isempty(m->wall_message) ? "" : "\n", isempty(m->wall_message) ? "" : "\n",
handle_action_to_string(manager_handle_for_item(m->scheduled_shutdown_type)), handle_action_to_string(m->scheduled_shutdown_type->handle),
left ? "at " : "NOW", left ? "at " : "NOW",
left ? FORMAT_TIMESTAMP(m->scheduled_shutdown_timeout) : ""); left ? FORMAT_TIMESTAMP(m->scheduled_shutdown_timeout) : "");
if (r < 0) { if (r < 0) {

View File

@ -848,10 +848,6 @@ int link_drop_foreign_addresses(Link *link) {
assert(link); assert(link);
assert(link->network); assert(link->network);
/* Keep all addresses when KeepConfiguration=yes. */
if (link->network->keep_configuration == KEEP_CONFIGURATION_YES)
return 0;
/* First, mark all addresses. */ /* First, mark all addresses. */
SET_FOREACH(address, link->addresses) { SET_FOREACH(address, link->addresses) {
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */ /* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */

View File

@ -1240,10 +1240,13 @@ static int link_reconfigure_impl(Link *link, bool force) {
link_drop_requests(link); link_drop_requests(link);
if (network && !force) if (network && !force && network->keep_configuration != KEEP_CONFIGURATION_YES)
/* When a new/updated .network file is assigned, first make all configs (addresses, /* When a new/updated .network file is assigned, first make all configs (addresses,
* routes, and so on) foreign, and then drop unnecessary configs later by * routes, and so on) foreign, and then drop unnecessary configs later by
* link_drop_foreign_config() in link_configure(). */ * link_drop_foreign_config() in link_configure().
* Note, when KeepConfiguration=yes, link_drop_foreign_config() does nothing. Hence,
* here we need to drop the configs such as addresses, routes, and so on configured by
* the previously assigned .network file. */
link_foreignize_config(link); link_foreignize_config(link);
else { else {
/* Remove all managed configs. Note, foreign configs are removed in later by /* Remove all managed configs. Note, foreign configs are removed in later by

View File

@ -3453,7 +3453,7 @@ static int inner_child(
assert(!sd_id128_is_null(arg_uuid)); assert(!sd_id128_is_null(arg_uuid));
if (asprintf(envp + n_env++, "container_uuid=%s", ID128_TO_UUID_STRING(arg_uuid)) < 0) if (asprintf(envp + n_env++, "container_uuid=%s", SD_ID128_TO_UUID_STRING(arg_uuid)) < 0)
return log_oom(); return log_oom();
if (fdset_size(fds) > 0) { if (fdset_size(fds) > 0) {

View File

@ -1512,11 +1512,11 @@ static int fdisk_ask_cb(struct fdisk_context *c, struct fdisk_ask *ask, void *da
if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_STRING) if (fdisk_ask_get_type(ask) != FDISK_ASKTYPE_STRING)
return -EINVAL; return -EINVAL;
ids = new(char, ID128_UUID_STRING_MAX); ids = new(char, SD_ID128_UUID_STRING_MAX);
if (!ids) if (!ids)
return -ENOMEM; return -ENOMEM;
r = fdisk_ask_string_set_result(ask, id128_to_uuid_string(*(sd_id128_t*) data, ids)); r = fdisk_ask_string_set_result(ask, sd_id128_to_uuid_string(*(sd_id128_t*) data, ids));
if (r < 0) if (r < 0)
return r; return r;
@ -2030,7 +2030,7 @@ static int context_dump_partitions(Context *context, const char *node) {
LIST_FOREACH(partitions, p, context->partitions) { LIST_FOREACH(partitions, p, context->partitions) {
_cleanup_free_ char *size_change = NULL, *padding_change = NULL, *partname = NULL; _cleanup_free_ char *size_change = NULL, *padding_change = NULL, *partname = NULL;
char uuid_buffer[ID128_UUID_STRING_MAX]; char uuid_buffer[SD_ID128_UUID_STRING_MAX];
const char *label, *activity = NULL; const char *label, *activity = NULL;
if (p->dropped) if (p->dropped)
@ -2176,7 +2176,7 @@ static int partition_hint(const Partition *p, const char *node, char **ret) {
else else
id = p->type_uuid; id = p->type_uuid;
buf = strdup(ID128_TO_UUID_STRING(id)); buf = strdup(SD_ID128_TO_UUID_STRING(id));
done: done:
if (!buf) if (!buf)
@ -2624,7 +2624,7 @@ static int partition_encrypt(
CRYPT_LUKS2, CRYPT_LUKS2,
"aes", "aes",
"xts-plain64", "xts-plain64",
ID128_TO_UUID_STRING(uuid), SD_ID128_TO_UUID_STRING(uuid),
volume_key, volume_key,
volume_key_size, volume_key_size,
&(struct crypt_params_luks2) { &(struct crypt_params_luks2) {
@ -3304,7 +3304,7 @@ static uint64_t partition_merge_flags(Partition *p) {
if (gpt_partition_type_knows_no_auto(p->type_uuid)) if (gpt_partition_type_knows_no_auto(p->type_uuid))
SET_FLAG(f, GPT_FLAG_NO_AUTO, p->no_auto); SET_FLAG(f, GPT_FLAG_NO_AUTO, p->no_auto);
else { else {
char buffer[ID128_UUID_STRING_MAX]; char buffer[SD_ID128_UUID_STRING_MAX];
log_warning("Configured NoAuto=%s for partition type '%s' that doesn't support it, ignoring.", log_warning("Configured NoAuto=%s for partition type '%s' that doesn't support it, ignoring.",
yes_no(p->no_auto), yes_no(p->no_auto),
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer)); gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
@ -3315,7 +3315,7 @@ static uint64_t partition_merge_flags(Partition *p) {
if (gpt_partition_type_knows_read_only(p->type_uuid)) if (gpt_partition_type_knows_read_only(p->type_uuid))
SET_FLAG(f, GPT_FLAG_READ_ONLY, p->read_only); SET_FLAG(f, GPT_FLAG_READ_ONLY, p->read_only);
else { else {
char buffer[ID128_UUID_STRING_MAX]; char buffer[SD_ID128_UUID_STRING_MAX];
log_warning("Configured ReadOnly=%s for partition type '%s' that doesn't support it, ignoring.", log_warning("Configured ReadOnly=%s for partition type '%s' that doesn't support it, ignoring.",
yes_no(p->read_only), yes_no(p->read_only),
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer)); gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
@ -3326,7 +3326,7 @@ static uint64_t partition_merge_flags(Partition *p) {
if (gpt_partition_type_knows_growfs(p->type_uuid)) if (gpt_partition_type_knows_growfs(p->type_uuid))
SET_FLAG(f, GPT_FLAG_GROWFS, p->growfs); SET_FLAG(f, GPT_FLAG_GROWFS, p->growfs);
else { else {
char buffer[ID128_UUID_STRING_MAX]; char buffer[SD_ID128_UUID_STRING_MAX];
log_warning("Configured GrowFileSystem=%s for partition type '%s' that doesn't support it, ignoring.", log_warning("Configured GrowFileSystem=%s for partition type '%s' that doesn't support it, ignoring.",
yes_no(p->growfs), yes_no(p->growfs),
gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer)); gpt_partition_type_uuid_to_string_harder(p->type_uuid, buffer));
@ -3374,7 +3374,7 @@ static int context_mangle_partitions(Context *context) {
if (!sd_id128_equal(p->new_uuid, p->current_uuid)) { if (!sd_id128_equal(p->new_uuid, p->current_uuid)) {
assert(!sd_id128_is_null(p->new_uuid)); assert(!sd_id128_is_null(p->new_uuid));
r = fdisk_partition_set_uuid(p->current_partition, ID128_TO_UUID_STRING(p->new_uuid)); r = fdisk_partition_set_uuid(p->current_partition, SD_ID128_TO_UUID_STRING(p->new_uuid));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set partition UUID: %m"); return log_error_errno(r, "Failed to set partition UUID: %m");
@ -3412,7 +3412,7 @@ static int context_mangle_partitions(Context *context) {
if (!t) if (!t)
return log_oom(); return log_oom();
r = fdisk_parttype_set_typestr(t, ID128_TO_UUID_STRING(p->type_uuid)); r = fdisk_parttype_set_typestr(t, SD_ID128_TO_UUID_STRING(p->type_uuid));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to initialize partition type: %m"); return log_error_errno(r, "Failed to initialize partition type: %m");
@ -3440,7 +3440,7 @@ static int context_mangle_partitions(Context *context) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set partition number: %m"); return log_error_errno(r, "Failed to set partition number: %m");
r = fdisk_partition_set_uuid(q, ID128_TO_UUID_STRING(p->new_uuid)); r = fdisk_partition_set_uuid(q, SD_ID128_TO_UUID_STRING(p->new_uuid));
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to set partition UUID: %m"); return log_error_errno(r, "Failed to set partition UUID: %m");

View File

@ -41,8 +41,7 @@ int manager_check_resolv_conf(const Manager *m) {
/* Is it symlinked to our own uplink file? */ /* Is it symlinked to our own uplink file? */
if (stat(PRIVATE_STATIC_RESOLV_CONF, &own) >= 0 && if (stat(PRIVATE_STATIC_RESOLV_CONF, &own) >= 0 &&
st.st_dev == own.st_dev && stat_inode_same(&st, &own))
st.st_ino == own.st_ino)
return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"DNSStubListener= is disabled, but /etc/resolv.conf is a symlink to " "DNSStubListener= is disabled, but /etc/resolv.conf is a symlink to "
PRIVATE_STATIC_RESOLV_CONF " which expects DNSStubListener= to be enabled."); PRIVATE_STATIC_RESOLV_CONF " which expects DNSStubListener= to be enabled.");
@ -64,8 +63,7 @@ static bool file_is_our_own(const struct stat *st) {
/* Is it symlinked to our own uplink file? */ /* Is it symlinked to our own uplink file? */
if (stat(path, &own) >= 0 && if (stat(path, &own) >= 0 &&
st->st_dev == own.st_dev && stat_inode_same(st, &own))
st->st_ino == own.st_ino)
return true; return true;
} }
@ -418,8 +416,7 @@ int resolv_conf_mode(void) {
continue; continue;
} }
if (system_st.st_dev == our_st.st_dev && if (stat_inode_same(&system_st, &our_st))
system_st.st_ino == our_st.st_ino)
return m; return m;
} }

View File

@ -22,6 +22,8 @@
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "gpt.h"
#include "id128-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h" #include "path-util.h"
#include "pe-header.h" #include "pe-header.h"
@ -51,6 +53,7 @@ static void boot_entry_free(BootEntry *entry) {
free(entry->efi); free(entry->efi);
strv_free(entry->initrd); strv_free(entry->initrd);
free(entry->device_tree); free(entry->device_tree);
strv_free(entry->device_tree_overlay);
} }
static int boot_entry_load( static int boot_entry_load(
@ -64,26 +67,28 @@ static int boot_entry_load(
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
unsigned line = 1; unsigned line = 1;
char *b, *c; char *c;
int r; int r;
assert(root); assert(root);
assert(path); assert(path);
assert(entry); assert(entry);
c = endswith_no_case(path, ".conf"); r = path_extract_filename(path, &tmp.id);
if (!c) if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry file suffix: %s", path); return log_error_errno(r, "Failed to extract file name from path '%s': %m", path);
b = basename(path); c = endswith_no_case(tmp.id, ".conf");
tmp.id = strdup(b); if (!c)
tmp.id_old = strndup(b, c - b); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry file suffix: %s", tmp.id);
if (!tmp.id || !tmp.id_old)
return log_oom();
if (!efi_loader_entry_name_valid(tmp.id)) if (!efi_loader_entry_name_valid(tmp.id))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry name: %s", tmp.id);
tmp.id_old = strndup(tmp.id, c - tmp.id);
if (!tmp.id_old)
return log_oom();
tmp.path = strdup(path); tmp.path = strdup(path);
if (!tmp.path) if (!tmp.path)
return log_oom(); return log_oom();
@ -142,7 +147,15 @@ static int boot_entry_load(
r = strv_extend(&tmp.initrd, p); r = strv_extend(&tmp.initrd, p);
else if (streq(field, "devicetree")) else if (streq(field, "devicetree"))
r = free_and_strdup(&tmp.device_tree, p); r = free_and_strdup(&tmp.device_tree, p);
else { else if (streq(field, "devicetree-overlay")) {
_cleanup_strv_free_ char **l = NULL;
l = strv_split(p, NULL);
if (!l)
return log_oom();
r = strv_extend_strv(&tmp.device_tree_overlay, l, false);
} else {
log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field); log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
continue; continue;
} }
@ -167,9 +180,11 @@ void boot_config_free(BootConfig *config) {
free(config->auto_firmware); free(config->auto_firmware);
free(config->console_mode); free(config->console_mode);
free(config->random_seed_mode); free(config->random_seed_mode);
free(config->beep);
free(config->entry_oneshot); free(config->entry_oneshot);
free(config->entry_default); free(config->entry_default);
free(config->entry_selected);
for (i = 0; i < config->n_entries; i++) for (i = 0; i < config->n_entries; i++)
boot_entry_free(config->entries + i); boot_entry_free(config->entries + i);
@ -234,6 +249,8 @@ static int boot_loader_read_conf(const char *path, BootConfig *config) {
r = free_and_strdup(&config->console_mode, p); r = free_and_strdup(&config->console_mode, p);
else if (streq(field, "random-seed-mode")) else if (streq(field, "random-seed-mode"))
r = free_and_strdup(&config->random_seed_mode, p); r = free_and_strdup(&config->random_seed_mode, p);
else if (streq(field, "beep"))
r = free_and_strdup(&config->beep, p);
else { else {
log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field); log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
continue; continue;
@ -546,18 +563,17 @@ static int boot_entries_find_unified(
return 0; return 0;
} }
static bool find_nonunique(BootEntry *entries, size_t n_entries, bool *arr) { static bool find_nonunique(const BootEntry *entries, size_t n_entries, bool arr[]) {
size_t i, j;
bool non_unique = false; bool non_unique = false;
assert(entries || n_entries == 0); assert(entries || n_entries == 0);
assert(arr || n_entries == 0); assert(arr || n_entries == 0);
for (i = 0; i < n_entries; i++) for (size_t i = 0; i < n_entries; i++)
arr[i] = false; arr[i] = false;
for (i = 0; i < n_entries; i++) for (size_t i = 0; i < n_entries; i++)
for (j = 0; j < n_entries; j++) for (size_t j = 0; j < n_entries; j++)
if (i != j && streq(boot_entry_title(entries + i), if (i != j && streq(boot_entry_title(entries + i),
boot_entry_title(entries + j))) boot_entry_title(entries + j)))
non_unique = arr[i] = arr[j] = true; non_unique = arr[i] = arr[j] = true;
@ -566,22 +582,26 @@ static bool find_nonunique(BootEntry *entries, size_t n_entries, bool *arr) {
} }
static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) { static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) {
_cleanup_free_ bool *arr = NULL;
char *s; char *s;
size_t i;
int r;
bool arr[n_entries];
assert(entries || n_entries == 0); assert(entries || n_entries == 0);
if (n_entries == 0)
return 0;
arr = new(bool, n_entries);
if (!arr)
return -ENOMEM;
/* Find _all_ non-unique titles */ /* Find _all_ non-unique titles */
if (!find_nonunique(entries, n_entries, arr)) if (!find_nonunique(entries, n_entries, arr))
return 0; return 0;
/* Add version to non-unique titles */ /* Add version to non-unique titles */
for (i = 0; i < n_entries; i++) for (size_t i = 0; i < n_entries; i++)
if (arr[i] && entries[i].version) { if (arr[i] && entries[i].version) {
r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].version); if (asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].version) < 0)
if (r < 0)
return -ENOMEM; return -ENOMEM;
free_and_replace(entries[i].show_title, s); free_and_replace(entries[i].show_title, s);
@ -591,10 +611,9 @@ static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) {
return 0; return 0;
/* Add machine-id to non-unique titles */ /* Add machine-id to non-unique titles */
for (i = 0; i < n_entries; i++) for (size_t i = 0; i < n_entries; i++)
if (arr[i] && entries[i].machine_id) { if (arr[i] && entries[i].machine_id) {
r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].machine_id); if (asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].machine_id) < 0)
if (r < 0)
return -ENOMEM; return -ENOMEM;
free_and_replace(entries[i].show_title, s); free_and_replace(entries[i].show_title, s);
@ -604,10 +623,9 @@ static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) {
return 0; return 0;
/* Add file name to non-unique titles */ /* Add file name to non-unique titles */
for (i = 0; i < n_entries; i++) for (size_t i = 0; i < n_entries; i++)
if (arr[i]) { if (arr[i]) {
r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].id); if (asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].id) < 0)
if (r < 0)
return -ENOMEM; return -ENOMEM;
free_and_replace(entries[i].show_title, s); free_and_replace(entries[i].show_title, s);
@ -655,6 +673,55 @@ static int boot_entries_select_default(const BootConfig *config) {
return config->n_entries - 1; return config->n_entries - 1;
} }
static int boot_entries_select_selected(const BootConfig *config) {
assert(config);
assert(config->entries || config->n_entries == 0);
if (!config->entry_selected || config->n_entries == 0)
return -1;
for (int i = config->n_entries - 1; i >= 0; i--)
if (streq(config->entry_selected, config->entries[i].id))
return i;
return -1;
}
static int boot_load_efi_entry_pointers(BootConfig *config) {
int r;
assert(config);
if (!is_efi_boot())
return 0;
/* Loads the three "pointers" to boot loader entries from their EFI variables */
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &config->entry_oneshot);
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryOneShot\": %m");
if (r == -ENOMEM)
return r;
}
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryDefault), &config->entry_default);
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\": %m");
if (r == -ENOMEM)
return r;
}
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntrySelected), &config->entry_selected);
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntrySelected\": %m");
if (r == -ENOMEM)
return r;
}
return 1;
}
int boot_entries_load_config( int boot_entries_load_config(
const char *esp_path, const char *esp_path,
const char *xbootldr_path, const char *xbootldr_path,
@ -700,23 +767,13 @@ int boot_entries_load_config(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to uniquify boot entries: %m"); return log_error_errno(r, "Failed to uniquify boot entries: %m");
if (is_efi_boot()) { r = boot_load_efi_entry_pointers(config);
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &config->entry_oneshot); if (r < 0)
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryOneShot\": %m");
if (r == -ENOMEM)
return r; return r;
}
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryDefault), &config->entry_default);
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\": %m");
if (r == -ENOMEM)
return r;
}
}
config->default_entry = boot_entries_select_default(config); config->default_entry = boot_entries_select_default(config);
config->selected_entry = boot_entries_select_selected(config);
return 0; return 0;
} }
@ -726,6 +783,7 @@ int boot_entries_load_config_auto(
BootConfig *config) { BootConfig *config) {
_cleanup_free_ char *esp_where = NULL, *xbootldr_where = NULL; _cleanup_free_ char *esp_where = NULL, *xbootldr_where = NULL;
dev_t esp_devid = 0, xbootldr_devid = 0;
int r; int r;
assert(config); assert(config);
@ -746,20 +804,25 @@ int boot_entries_load_config_auto(
"Failed to determine whether /run/boot-loader-entries/ exists: %m"); "Failed to determine whether /run/boot-loader-entries/ exists: %m");
} }
r = find_esp_and_warn(override_esp_path, false, &esp_where, NULL, NULL, NULL, NULL); r = find_esp_and_warn(override_esp_path, /* unprivileged_mode= */ false, &esp_where, NULL, NULL, NULL, NULL, &esp_devid);
if (r < 0) /* we don't log about ENOKEY here, but propagate it, leaving it to the caller to log */ if (r < 0) /* we don't log about ENOKEY here, but propagate it, leaving it to the caller to log */
return r; return r;
r = find_xbootldr_and_warn(override_xbootldr_path, false, &xbootldr_where, NULL); r = find_xbootldr_and_warn(override_xbootldr_path, /* unprivileged_mode= */ false, &xbootldr_where, NULL, &xbootldr_devid);
if (r < 0 && r != -ENOKEY) if (r < 0 && r != -ENOKEY)
return r; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */ return r; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */
/* If both paths actually refer to the same inode, suppress the xbootldr path */
if (esp_where && xbootldr_where && devid_set_and_equal(esp_devid, xbootldr_devid))
xbootldr_where = mfree(xbootldr_where);
return boot_entries_load_config(esp_where, xbootldr_where, config); return boot_entries_load_config(esp_where, xbootldr_where, config);
} }
int boot_entries_augment_from_loader( int boot_entries_augment_from_loader(
BootConfig *config, BootConfig *config,
char **found_by_loader) { char **found_by_loader,
bool only_auto) {
static const char *const title_table[] = { static const char *const title_table[] = {
/* Pretty names for a few well-known automatically discovered entries. */ /* Pretty names for a few well-known automatically discovered entries. */
@ -778,18 +841,17 @@ int boot_entries_augment_from_loader(
* already included there. */ * already included there. */
STRV_FOREACH(i, found_by_loader) { STRV_FOREACH(i, found_by_loader) {
BootEntry *existing;
_cleanup_free_ char *c = NULL, *t = NULL, *p = NULL; _cleanup_free_ char *c = NULL, *t = NULL, *p = NULL;
char **a, **b; char **a, **b;
if (boot_config_has_entry(config, *i)) existing = boot_config_find_entry(config, *i);
if (existing) {
existing->reported_by_loader = true;
continue; continue;
}
/* if (only_auto && !startswith(*i, "auto-"))
* consider the 'auto-' entries only, because the others
* ones are detected scanning the 'esp' and 'xbootldr'
* directories by boot_entries_load_config()
*/
if (!startswith(*i, "auto-"))
continue; continue;
c = strdup(*i); c = strdup(*i);
@ -812,10 +874,11 @@ int boot_entries_augment_from_loader(
return log_oom(); return log_oom();
config->entries[config->n_entries++] = (BootEntry) { config->entries[config->n_entries++] = (BootEntry) {
.type = BOOT_ENTRY_LOADER, .type = startswith(*i, "auto-") ? BOOT_ENTRY_LOADER_AUTO : BOOT_ENTRY_LOADER,
.id = TAKE_PTR(c), .id = TAKE_PTR(c),
.title = TAKE_PTR(t), .title = TAKE_PTR(t),
.path = TAKE_PTR(p), .path = TAKE_PTR(p),
.reported_by_loader = true,
}; };
} }
@ -889,7 +952,7 @@ static int verify_esp_blkid(
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node); return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) if (id128_equal_string(v, GPT_ESP) <= 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node); "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
@ -982,7 +1045,7 @@ static int verify_esp_udev(
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_error_errno(r, "Failed to get device property: %m");
if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) if (id128_equal_string(v, GPT_ESP) <= 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node); "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
@ -1107,7 +1170,8 @@ static int verify_esp(
uint32_t *ret_part, uint32_t *ret_part,
uint64_t *ret_pstart, uint64_t *ret_pstart,
uint64_t *ret_psize, uint64_t *ret_psize,
sd_id128_t *ret_uuid) { sd_id128_t *ret_uuid,
dev_t *ret_devid) {
bool relax_checks; bool relax_checks;
dev_t devid; dev_t devid;
@ -1157,9 +1221,16 @@ static int verify_esp(
* however blkid can't work if we have no privileges to access block devices directly, which is why * however blkid can't work if we have no privileges to access block devices directly, which is why
* we use udev in that case. */ * we use udev in that case. */
if (unprivileged_mode) if (unprivileged_mode)
return verify_esp_udev(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid); r = verify_esp_udev(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
else else
return verify_esp_blkid(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid); r = verify_esp_blkid(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
if (r < 0)
return r;
if (ret_devid)
*ret_devid = devid;
return 0;
finish: finish:
if (ret_part) if (ret_part)
@ -1170,6 +1241,8 @@ finish:
*ret_psize = 0; *ret_psize = 0;
if (ret_uuid) if (ret_uuid)
*ret_uuid = SD_ID128_NULL; *ret_uuid = SD_ID128_NULL;
if (ret_devid)
*ret_devid = 0;
return 0; return 0;
} }
@ -1181,7 +1254,8 @@ int find_esp_and_warn(
uint32_t *ret_part, uint32_t *ret_part,
uint64_t *ret_pstart, uint64_t *ret_pstart,
uint64_t *ret_psize, uint64_t *ret_psize,
sd_id128_t *ret_uuid) { sd_id128_t *ret_uuid,
dev_t *ret_devid) {
int r; int r;
@ -1192,7 +1266,7 @@ int find_esp_and_warn(
*/ */
if (path) { if (path) {
r = verify_esp(path, false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid); r = verify_esp(path, /* searching= */ false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid);
if (r < 0) if (r < 0)
return r; return r;
@ -1201,19 +1275,39 @@ int find_esp_and_warn(
path = getenv("SYSTEMD_ESP_PATH"); path = getenv("SYSTEMD_ESP_PATH");
if (path) { if (path) {
struct stat st;
if (!path_is_valid(path) || !path_is_absolute(path)) if (!path_is_valid(path) || !path_is_absolute(path))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s", "$SYSTEMD_ESP_PATH does not refer to absolute path, refusing to use it: %s",
path); path);
/* Note: when the user explicitly configured things with an env var we won't validate the mount /* Note: when the user explicitly configured things with an env var we won't validate the
* point. After all we want this to be useful for testing. */ * path beyond checking it refers to a directory. After all we want this to be useful for
* testing. */
if (stat(path, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", path);
if (!S_ISDIR(st.st_mode))
return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "ESP path '%s' is not a directory.", path);
if (ret_part)
*ret_part = 0;
if (ret_pstart)
*ret_pstart = 0;
if (ret_psize)
*ret_psize = 0;
if (ret_uuid)
*ret_uuid = SD_ID128_NULL;
if (ret_devid)
*ret_devid = st.st_dev;
goto found; goto found;
} }
FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") { FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") {
r = verify_esp(path, true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid); r = verify_esp(path, /* searching= */ true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid);
if (r >= 0) if (r >= 0)
goto found; goto found;
if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */ if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
@ -1280,7 +1374,7 @@ static int verify_xbootldr_blkid(
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node); return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172")) if (id128_equal_string(v, GPT_XBOOTLDR) <= 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV), searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
"File system \"%s\" has wrong type for extended boot loader partition.", node); "File system \"%s\" has wrong type for extended boot loader partition.", node);
@ -1344,7 +1438,7 @@ static int verify_xbootldr_udev(
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_error_errno(r, "Failed to get device property: %m");
if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172")) if (id128_equal_string(v, GPT_XBOOTLDR))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV), searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
"File system \"%s\" has wrong type for extended boot loader partition.", node); "File system \"%s\" has wrong type for extended boot loader partition.", node);
@ -1380,7 +1474,8 @@ static int verify_xbootldr(
const char *p, const char *p,
bool searching, bool searching,
bool unprivileged_mode, bool unprivileged_mode,
sd_id128_t *ret_uuid) { sd_id128_t *ret_uuid,
dev_t *ret_devid) {
bool relax_checks; bool relax_checks;
dev_t devid; dev_t devid;
@ -1398,13 +1493,22 @@ static int verify_xbootldr(
goto finish; goto finish;
if (unprivileged_mode) if (unprivileged_mode)
return verify_xbootldr_udev(devid, searching, ret_uuid); r = verify_xbootldr_udev(devid, searching, ret_uuid);
else else
return verify_xbootldr_blkid(devid, searching, ret_uuid); r = verify_xbootldr_blkid(devid, searching, ret_uuid);
if (r < 0)
return r;
if (ret_devid)
*ret_devid = devid;
return 0;
finish: finish:
if (ret_uuid) if (ret_uuid)
*ret_uuid = SD_ID128_NULL; *ret_uuid = SD_ID128_NULL;
if (ret_devid)
*ret_devid = 0;
return 0; return 0;
} }
@ -1413,14 +1517,15 @@ int find_xbootldr_and_warn(
const char *path, const char *path,
bool unprivileged_mode, bool unprivileged_mode,
char **ret_path, char **ret_path,
sd_id128_t *ret_uuid) { sd_id128_t *ret_uuid,
dev_t *ret_devid) {
int r; int r;
/* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */ /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
if (path) { if (path) {
r = verify_xbootldr(path, false, unprivileged_mode, ret_uuid); r = verify_xbootldr(path, /* searching= */ false, unprivileged_mode, ret_uuid, ret_devid);
if (r < 0) if (r < 0)
return r; return r;
@ -1429,15 +1534,27 @@ int find_xbootldr_and_warn(
path = getenv("SYSTEMD_XBOOTLDR_PATH"); path = getenv("SYSTEMD_XBOOTLDR_PATH");
if (path) { if (path) {
struct stat st;
if (!path_is_valid(path) || !path_is_absolute(path)) if (!path_is_valid(path) || !path_is_absolute(path))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s", "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
path); path);
if (stat(path, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", path);
if (!S_ISDIR(st.st_mode))
return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR), "XBOOTLDR path '%s' is not a directory.", path);
if (ret_uuid)
*ret_uuid = SD_ID128_NULL;
if (ret_devid)
*ret_devid = st.st_dev;
goto found; goto found;
} }
r = verify_xbootldr("/boot", true, unprivileged_mode, ret_uuid); r = verify_xbootldr("/boot", true, unprivileged_mode, ret_uuid, ret_devid);
if (r >= 0) { if (r >= 0) {
path = "/boot"; path = "/boot";
goto found; goto found;

View File

@ -11,15 +11,17 @@
#include "string-util.h" #include "string-util.h"
typedef enum BootEntryType { typedef enum BootEntryType {
BOOT_ENTRY_CONF, /* Type #1 entries: *.conf files */ BOOT_ENTRY_CONF, /* Boot Loader Specification Type #1 entries: *.conf files */
BOOT_ENTRY_UNIFIED, /* Type #2 entries: *.efi files */ BOOT_ENTRY_UNIFIED, /* Boot Loader Specification Type #2 entries: *.efi files */
BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI var */ BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI variable (regular entries) */
_BOOT_ENTRY_MAX, BOOT_ENTRY_LOADER_AUTO, /* Additional entries augmented from LoaderEntries EFI variable (special "automatic" entries) */
_BOOT_ENTRY_INVALID = -EINVAL, _BOOT_ENTRY_TYPE_MAX,
_BOOT_ENTRY_TYPE_INVALID = -EINVAL,
} BootEntryType; } BootEntryType;
typedef struct BootEntry { typedef struct BootEntry {
BootEntryType type; BootEntryType type;
bool reported_by_loader;
char *id; /* This is the file basename (including extension!) */ char *id; /* This is the file basename (including extension!) */
char *id_old; /* Old-style ID, for deduplication purposes. */ char *id_old; /* Old-style ID, for deduplication purposes. */
char *path; /* This is the full path to the drop-in file */ char *path; /* This is the full path to the drop-in file */
@ -34,6 +36,7 @@ typedef struct BootEntry {
char *efi; char *efi;
char **initrd; char **initrd;
char *device_tree; char *device_tree;
char **device_tree_overlay;
} BootEntry; } BootEntry;
typedef struct BootConfig { typedef struct BootConfig {
@ -44,29 +47,33 @@ typedef struct BootConfig {
char *auto_firmware; char *auto_firmware;
char *console_mode; char *console_mode;
char *random_seed_mode; char *random_seed_mode;
char *beep;
char *entry_oneshot; char *entry_oneshot;
char *entry_default; char *entry_default;
char *entry_selected;
BootEntry *entries; BootEntry *entries;
size_t n_entries; size_t n_entries;
ssize_t default_entry; ssize_t default_entry;
ssize_t selected_entry;
} BootConfig; } BootConfig;
static inline bool boot_config_has_entry(BootConfig *config, const char *id) { static inline BootEntry* boot_config_find_entry(BootConfig *config, const char *id) {
size_t j; assert(config);
assert(id);
for (j = 0; j < config->n_entries; j++) { for (size_t j = 0; j < config->n_entries; j++)
const char* entry_id_old = config->entries[j].id_old; if (streq_ptr(config->entries[j].id, id) ||
if (streq(config->entries[j].id, id) || streq_ptr(config->entries[j].id_old, id))
(entry_id_old && streq(entry_id_old, id))) return config->entries + j;
return true;
}
return false; return NULL;
} }
static inline BootEntry* boot_config_default_entry(BootConfig *config) { static inline BootEntry* boot_config_default_entry(BootConfig *config) {
assert(config);
if (config->default_entry < 0) if (config->default_entry < 0)
return NULL; return NULL;
@ -76,11 +83,13 @@ static inline BootEntry* boot_config_default_entry(BootConfig *config) {
void boot_config_free(BootConfig *config); void boot_config_free(BootConfig *config);
int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config); int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config);
int boot_entries_load_config_auto(const char *override_esp_path, const char *override_xbootldr_path, BootConfig *config); int boot_entries_load_config_auto(const char *override_esp_path, const char *override_xbootldr_path, BootConfig *config);
int boot_entries_augment_from_loader(BootConfig *config, char **list); int boot_entries_augment_from_loader(BootConfig *config, char **list, bool only_auto);
static inline const char* boot_entry_title(const BootEntry *entry) { static inline const char* boot_entry_title(const BootEntry *entry) {
assert(entry);
return entry->show_title ?: entry->title ?: entry->id; return entry->show_title ?: entry->title ?: entry->id;
} }
int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid); int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid, dev_t *ret_devid);
int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid); int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid, dev_t *ret_devid);

View File

@ -1699,11 +1699,11 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
case TABLE_UUID: { case TABLE_UUID: {
char *p; char *p;
p = new(char, ID128_UUID_STRING_MAX); p = new(char, SD_ID128_UUID_STRING_MAX);
if (!p) if (!p)
return NULL; return NULL;
d->formatted = id128_to_uuid_string(d->id128, p); d->formatted = sd_id128_to_uuid_string(d->id128, p);
break; break;
} }
@ -2562,7 +2562,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
return json_variant_new_string(ret, SD_ID128_TO_STRING(d->id128)); return json_variant_new_string(ret, SD_ID128_TO_STRING(d->id128));
case TABLE_UUID: case TABLE_UUID:
return json_variant_new_string(ret, ID128_TO_UUID_STRING(d->id128)); return json_variant_new_string(ret, SD_ID128_TO_UUID_STRING(d->id128));
case TABLE_UID: case TABLE_UID:
if (!uid_is_valid(d->uid)) if (!uid_is_valid(d->uid))

View File

@ -75,7 +75,7 @@ const char *gpt_partition_type_uuid_to_string(sd_id128_t id) {
const char *gpt_partition_type_uuid_to_string_harder( const char *gpt_partition_type_uuid_to_string_harder(
sd_id128_t id, sd_id128_t id,
char buffer[static ID128_UUID_STRING_MAX]) { char buffer[static SD_ID128_UUID_STRING_MAX]) {
const char *s; const char *s;
@ -85,7 +85,7 @@ const char *gpt_partition_type_uuid_to_string_harder(
if (s) if (s)
return s; return s;
return id128_to_uuid_string(id, buffer); return sd_id128_to_uuid_string(id, buffer);
} }
int gpt_partition_type_uuid_from_string(const char *s, sd_id128_t *ret) { int gpt_partition_type_uuid_from_string(const char *s, sd_id128_t *ret) {

View File

@ -286,7 +286,7 @@
const char *gpt_partition_type_uuid_to_string(sd_id128_t id); const char *gpt_partition_type_uuid_to_string(sd_id128_t id);
const char *gpt_partition_type_uuid_to_string_harder( const char *gpt_partition_type_uuid_to_string_harder(
sd_id128_t id, sd_id128_t id,
char buffer[static ID128_UUID_STRING_MAX]); char buffer[static SD_ID128_UUID_STRING_MAX]);
int gpt_partition_type_uuid_from_string(const char *s, sd_id128_t *ret); int gpt_partition_type_uuid_from_string(const char *s, sd_id128_t *ret);
Architecture gpt_partition_type_uuid_to_arch(sd_id128_t id); Architecture gpt_partition_type_uuid_to_arch(sd_id128_t id);

View File

@ -1510,7 +1510,7 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
_cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_close_pair_ int pair[2] = { -1, -1 };
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
char buf[ID128_UUID_STRING_MAX]; char buf[SD_ID128_UUID_STRING_MAX];
pid_t pid, child; pid_t pid, child;
ssize_t k; ssize_t k;
int r; int r;

View File

@ -94,7 +94,7 @@ int make_filesystem(
bool discard) { bool discard) {
_cleanup_free_ char *mkfs = NULL, *mangled_label = NULL; _cleanup_free_ char *mkfs = NULL, *mangled_label = NULL;
char vol_id[CONST_MAX(ID128_UUID_STRING_MAX, 8 + 1)] = {}; char vol_id[CONST_MAX(SD_ID128_UUID_STRING_MAX, 8U + 1U)] = {};
int r; int r;
assert(node); assert(node);
@ -144,7 +144,7 @@ int make_filesystem(
} }
if (isempty(vol_id)) if (isempty(vol_id))
id128_to_uuid_string(uuid, vol_id); assert_se(sd_id128_to_uuid_string(uuid, vol_id));
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, NULL); r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, NULL);
if (r < 0) if (r < 0)

View File

@ -816,7 +816,7 @@ static int mount_in_namespace(
return log_debug_errno(errno, "Failed to fstat mount namespace FD of systemd: %m"); return log_debug_errno(errno, "Failed to fstat mount namespace FD of systemd: %m");
/* We can't add new mounts at runtime if the process wasn't started in a namespace */ /* We can't add new mounts at runtime if the process wasn't started in a namespace */
if (st.st_ino == self_mntns_st.st_ino && st.st_dev == self_mntns_st.st_dev) if (stat_inode_same(&st, &self_mntns_st))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace"); return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
/* One day, when bind mounting /proc/self/fd/n works across namespace boundaries we should rework /* One day, when bind mounting /proc/self/fd/n works across namespace boundaries we should rework

View File

@ -351,7 +351,7 @@ void log_device_uevent(sd_device *device, const char *str) {
strempty(str), isempty(str) ? "" : " ", strempty(str), isempty(str) ? "" : " ",
seqnum, strna(device_action_to_string(action)), seqnum, strna(device_action_to_string(action)),
sd_id128_is_null(event_id) ? "" : ", UUID=", sd_id128_is_null(event_id) ? "" : ", UUID=",
sd_id128_is_null(event_id) ? "" : id128_to_uuid_string(event_id, (char[ID128_UUID_STRING_MAX]){})); sd_id128_is_null(event_id) ? "" : SD_ID128_TO_UUID_STRING(event_id));
} }
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {

View File

@ -12,6 +12,7 @@
#include "systemctl-compat-halt.h" #include "systemctl-compat-halt.h"
#include "systemctl-compat-telinit.h" #include "systemctl-compat-telinit.h"
#include "systemctl-logind.h" #include "systemctl-logind.h"
#include "systemctl-start-unit.h"
#include "systemctl-util.h" #include "systemctl-util.h"
#include "systemctl.h" #include "systemctl.h"
#include "terminal-util.h" #include "terminal-util.h"
@ -144,6 +145,7 @@ int halt_parse_argv(int argc, char *argv[]) {
int halt_main(void) { int halt_main(void) {
int r; int r;
if (arg_force == 0) {
/* always try logind first */ /* always try logind first */
if (arg_when > 0) if (arg_when > 0)
r = logind_schedule_shutdown(); r = logind_schedule_shutdown();
@ -166,8 +168,9 @@ int halt_main(void) {
* enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */ * enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */
arg_no_block = true; arg_no_block = true;
if (!arg_dry_run && !arg_force) if (!arg_dry_run)
return start_with_fallback(); return start_with_fallback();
}
if (geteuid() != 0) { if (geteuid() != 0) {
(void) must_be_root(); (void) must_be_root();

View File

@ -35,11 +35,14 @@ union sd_id128 {
}; };
#define SD_ID128_STRING_MAX 33U #define SD_ID128_STRING_MAX 33U
#define SD_ID128_UUID_STRING_MAX 37U
char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]); char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]);
char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_UUID_STRING_MAX]);
int sd_id128_from_string(const char *s, sd_id128_t *ret); int sd_id128_from_string(const char *s, sd_id128_t *ret);
#define SD_ID128_TO_STRING(id) sd_id128_to_string((id), (char[SD_ID128_STRING_MAX]) {}) #define SD_ID128_TO_STRING(id) sd_id128_to_string((id), (char[SD_ID128_STRING_MAX]) {})
#define SD_ID128_TO_UUID_STRING(id) sd_id128_to_uuid_string((id), (char[SD_ID128_UUID_STRING_MAX]) {})
int sd_id128_randomize(sd_id128_t *ret); int sd_id128_randomize(sd_id128_t *ret);

View File

@ -21,7 +21,7 @@
TEST(id128) { TEST(id128) {
sd_id128_t id, id2; sd_id128_t id, id2;
char t[SD_ID128_STRING_MAX], q[ID128_UUID_STRING_MAX]; char t[SD_ID128_STRING_MAX], q[SD_ID128_UUID_STRING_MAX];
_cleanup_free_ char *b = NULL; _cleanup_free_ char *b = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
@ -53,7 +53,7 @@ TEST(id128) {
printf("waldi2: %s\n", b); printf("waldi2: %s\n", b);
assert_se(streq(t, b)); assert_se(streq(t, b));
printf("waldi3: %s\n", id128_to_uuid_string(ID128_WALDI, q)); printf("waldi3: %s\n", sd_id128_to_uuid_string(ID128_WALDI, q));
assert_se(streq(q, UUID_WALDI)); assert_se(streq(q, UUID_WALDI));
b = mfree(b); b = mfree(b);
@ -136,7 +136,7 @@ TEST(id128) {
assert_se(ftruncate(fd, 0) >= 0); assert_se(ftruncate(fd, 0) >= 0);
assert_se(sd_id128_randomize(&id) >= 0); assert_se(sd_id128_randomize(&id) >= 0);
assert_se(write(fd, id128_to_uuid_string(id, q), 36) == 36); assert_se(write(fd, sd_id128_to_uuid_string(id, q), 36) == 36);
assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL);

View File

@ -285,7 +285,7 @@ static int determine_device(
if (!*data_what) { if (!*data_what) {
memcpy(&data_uuid, m, sizeof(data_uuid)); memcpy(&data_uuid, m, sizeof(data_uuid));
*data_what = path_join("/dev/disk/by-partuuid", ID128_TO_UUID_STRING(data_uuid)); *data_what = path_join("/dev/disk/by-partuuid", SD_ID128_TO_UUID_STRING(data_uuid));
if (!*data_what) if (!*data_what)
return log_oom(); return log_oom();
} }
@ -293,7 +293,7 @@ static int determine_device(
if (!*hash_what) { if (!*hash_what) {
memcpy(&verity_uuid, (uint8_t*) m + l - sizeof(verity_uuid), sizeof(verity_uuid)); memcpy(&verity_uuid, (uint8_t*) m + l - sizeof(verity_uuid), sizeof(verity_uuid));
*hash_what = path_join("/dev/disk/by-partuuid", ID128_TO_UUID_STRING(verity_uuid)); *hash_what = path_join("/dev/disk/by-partuuid", SD_ID128_TO_UUID_STRING(verity_uuid));
if (!*hash_what) if (!*hash_what)
return log_oom(); return log_oom();
} }

View File

@ -1070,6 +1070,9 @@ install_compiled_systemd() {
if get_bool "$IS_BUILT_WITH_COVERAGE"; then if get_bool "$IS_BUILT_WITH_COVERAGE"; then
mkdir -p "${initdir}/${BUILD_DIR:?}/" mkdir -p "${initdir}/${BUILD_DIR:?}/"
rsync -am --include='*/' --include='*.gcno' --exclude='*' "${BUILD_DIR:?}/" "${initdir}/${BUILD_DIR:?}/" rsync -am --include='*/' --include='*.gcno' --exclude='*' "${BUILD_DIR:?}/" "${initdir}/${BUILD_DIR:?}/"
# Set effective & default ACLs for the build dir so unprivileged
# processes can write gcda files with coverage stats
setfacl -R -m 'd:o:rwX' -m 'o:rwX' "${initdir}/${BUILD_DIR:?}/"
fi fi
} }
@ -1384,6 +1387,20 @@ check_coverage_reports() {
lcov --remove "${dest}" -o "${dest}" '/usr/include/*' '/usr/lib/*' lcov --remove "${dest}" -o "${dest}" '/usr/include/*' '/usr/lib/*'
fi fi
# If the test logs contain lines like:
#
# ...systemd-resolved[735885]: profiling:/systemd-meson-build/src/shared/libsystemd-shared-250.a.p/base-filesystem.c.gcda:Cannot open
#
# it means we're possibly missing some coverage since gcov can't write the stats,
# usually due to the sandbox being too restrictive (e.g. ProtectSystem=yes,
# ProtectHome=yes) or the $BUILD_DIR being inaccessible to non-root users - see
# `setfacl` stuff in install_compiled_systemd().
if "${JOURNALCTL:?}" -q --no-pager -D "${root:?}/var/log/journal" --grep "profiling:.+?gcda:[Cc]annot open"; then
derror "Detected possibly missing coverage, check the journal"
return 1
fi
return 0 return 0
} }