mirror of
https://github.com/systemd/systemd
synced 2026-03-13 00:24:48 +01:00
Compare commits
53 Commits
dd8c12e5ec
...
14519d7dfa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14519d7dfa | ||
|
|
779ed358f2 | ||
|
|
e67b008fa3 | ||
|
|
775f04293d | ||
|
|
7ae2329198 | ||
|
|
b026cb94ae | ||
|
|
df8747806b | ||
|
|
8a70fa901e | ||
|
|
25860000b6 | ||
|
|
71e651ba82 | ||
|
|
a1d3fd1202 | ||
|
|
e2f23b6deb | ||
|
|
607152c742 | ||
|
|
3e4fca7489 | ||
|
|
c0ee33f48f | ||
|
|
382f141fea | ||
|
|
4a54381d07 | ||
|
|
05bbe4247b | ||
|
|
2557f78c07 | ||
|
|
f5a7247afb | ||
|
|
780f15ee7d | ||
|
|
2c756c6964 | ||
|
|
15777d6d5c | ||
|
|
cfee2c1900 | ||
|
|
533afe86c3 | ||
|
|
7d4ea41bd1 | ||
|
|
8b7e98f183 | ||
|
|
a2e55fceee | ||
|
|
4834014018 | ||
|
|
a304f6c9db | ||
|
|
7e8c35ce80 | ||
|
|
cc9a9d6a15 | ||
|
|
18a8ea3377 | ||
|
|
294855953c | ||
|
|
3788ec1b4a | ||
|
|
2d34ff822b | ||
|
|
e180087038 | ||
|
|
9b09b11d21 | ||
|
|
a7aebb2250 | ||
|
|
1b9506601f | ||
|
|
6c051e84c7 | ||
|
|
3317ea84bc | ||
|
|
9fa9f10088 | ||
|
|
0ec663a41f | ||
|
|
1f8b09dfc6 | ||
|
|
75e1963df1 | ||
|
|
a537c5e4b8 | ||
|
|
1dad3b6762 | ||
|
|
9b29d38c33 | ||
|
|
91b3620b07 | ||
|
|
7ee2f6657f | ||
|
|
aea76373b2 | ||
|
|
38433a6d06 |
@ -38,4 +38,5 @@ Stable branches with backported patches are available in the [stable repo](https
|
||||
|
||||
We have a security bug bounty program sponsored by the [Sovereign Tech Fund](https://www.sovereigntechfund.de/) hosted on [YesWeHack](https://yeswehack.com/programs/systemd-bug-bounty-program)
|
||||
|
||||
Repositories with distribution packages built from git main are [available on OBS](https://software.opensuse.org//download.html?project=system%3Asystemd&package=systemd)
|
||||
Repositories with distribution packages built from git main are [available on OBS](https://software.opensuse.org//download.html?project=system%3Asystemd&package=systemd),
|
||||
and also repositories with [packages built from the latest stable release](https://software.opensuse.org//download.html?project=system%3Asystemd%3Astable&package=systemd)
|
||||
|
||||
19
TODO
19
TODO
@ -116,10 +116,25 @@ Deprecations and removals:
|
||||
|
||||
* Consider removing root=gpt-auto, and push people to use root=dissect instead.
|
||||
|
||||
* remove any trace of "cpuacct" cgroup controller, it's a cgroupv1 thing.
|
||||
similar "devices"
|
||||
|
||||
Features:
|
||||
|
||||
* mountfsd: when looking for non-foreign uid owned inodes up the tree, stop at
|
||||
mounts
|
||||
* report:
|
||||
- should the list of metrics use JSON-SEQ? or maybe be wrapped in a json
|
||||
array (the latter might be necessary, once we sign the combination)
|
||||
- "io.systemd.Manager.unit_active_state" is a weird mix of CamelCase and snake_case
|
||||
- metrics from pid1: suppress metrics form units that are inactive and have nothing to report
|
||||
- how to plug facts into this? i.e. hostname, ssh keys, and so on
|
||||
- switch to daan's suggested hierarchy?
|
||||
|
||||
* implement a varlink registry service, similar to the one of the reference
|
||||
implementation, backed by /run/varlink/registry/. Then, also implement
|
||||
connect-via-registry-resolution in sd-varlink and varlinkctl. Care needs to
|
||||
be taken to do the resolution asynchronousy. Also, note that the Varlink
|
||||
reference implementation uses a different address syntax, which needs to be
|
||||
taken into account.
|
||||
|
||||
* downgrade the uid/gid disposition enforcement in udev
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ Thus code that is used by "higher-level" components (e.g. our binaries which are
|
||||
would go to a subdirectory specific to that component if it is only used there.
|
||||
If the code is to be shared between components, it'd go to `src/shared/`.
|
||||
Shared code that is used by multiple components that do not link to `libsystemd-shared-<nnn>.so` may live either in `src/libsystemd/`, `src/basic/`, or `src/fundamental/`.
|
||||
Any code that is used only for EFI goes under `src/boot/efi/`, and in `src/fundamental/` if it is shared with non-EFI components.
|
||||
Code used only for EFI goes under `src/boot/`, and under `src/fundamental/` if it is shared with non-EFI components.
|
||||
|
||||
To summarize:
|
||||
|
||||
|
||||
@ -671,6 +671,10 @@ SYSTEMD_HOME_DEBUG_SUFFIX=foo \
|
||||
specified algorithm takes an effect immediately, you need to explicitly run
|
||||
`journalctl --rotate`.
|
||||
|
||||
* `$SYSTEMD_JOURNAL_FD_SIZE_MAX` – Takes a size with the usual suffixes (K, M, ...) in
|
||||
string format. Overrides the default maximum allowed size for a file-descriptor
|
||||
based input record to be stored in the journal.
|
||||
|
||||
* `$SYSTEMD_CATALOG` – path to the compiled catalog database file to use for
|
||||
`journalctl -x`, `journalctl --update-catalog`, `journalctl --list-catalog`
|
||||
and related calls.
|
||||
|
||||
@ -26,14 +26,15 @@ SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
17. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
|
||||
18. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
|
||||
19. [FINAL] Create an empty -stable branch: `git push systemd origin/main:refs/heads/v${version}-stable`.
|
||||
20. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
|
||||
21. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
|
||||
22. [FINAL] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.pkgenv/mkosi.conf.d/debian-ubuntu.conf`
|
||||
20. [FINAL] Edit in the new -stable branch `.obs/workflows.yml`, changing `project` from `system:systemd` to `system:systemd:stable` and the branch from `main` to `v${version}-stable`. This should be backported to older active stable branches too.
|
||||
21. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
|
||||
22. [FINAL] Create a new `ci/v${version}-stable` branch for deb package builds on https://salsa.debian.org/systemd-team/systemd
|
||||
23. [FINAL] Switch `.semaphore/semaphore-runner.sh` and `mkosi/mkosi.pkgenv/mkosi.conf.d/debian-ubuntu.conf`
|
||||
to the new `ci/v${version}-stable` branch on the -stable branch
|
||||
23. [FINAL] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to release mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
||||
24. [FINAL] Change the Github Pages branch to the newly created branch (https://github.com/systemd/systemd/settings/pages) and set the 'Custom domain' to 'systemd.io'
|
||||
25. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
|
||||
26. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
|
||||
24. [FINAL] Switch `versionrewrite-pattern` and `versionrewrite-replacement` to release mode in https://build.opensuse.org/projects/system:systemd/packages/systemd/files/_service?expand=1
|
||||
25. [FINAL] Change the Github Pages branch to the newly created branch (https://github.com/systemd/systemd/settings/pages) and set the 'Custom domain' to 'systemd.io'
|
||||
26. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `256` to `257~devel`)
|
||||
27. [FINAL] Build and upload the documentation (on the main branch): `ninja -C build doc-sync`
|
||||
|
||||
# Steps to a Successful Stable Release
|
||||
|
||||
|
||||
@ -266,12 +266,12 @@ def check_matches(groups):
|
||||
if gr:
|
||||
# we check this first to provide an easy error message
|
||||
if rest[-1] not in '*:':
|
||||
error('Pattern {} does not end with "*" or ":"', match)
|
||||
error('Pattern {!r} does not end with "*" or ":"', match)
|
||||
|
||||
try:
|
||||
gr.parseString(rest)
|
||||
except ParseBaseException as e:
|
||||
error('Pattern {} is invalid: {}', match, e)
|
||||
error('Pattern {!r} is invalid: {}', match, e)
|
||||
continue
|
||||
|
||||
matches.sort()
|
||||
@ -353,12 +353,11 @@ def print_summary(fname, groups):
|
||||
error(f'{fname}: no matches or props')
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv[1:] or sorted(
|
||||
[
|
||||
args = sys.argv[1:] or sorted([
|
||||
os.path.dirname(sys.argv[0]) + '/20-dmi-id.hwdb',
|
||||
os.path.dirname(sys.argv[0]) + '/20-net-ifname.hwdb',
|
||||
] + glob.glob(os.path.dirname(sys.argv[0]) + '/[678][0-9]-*.hwdb')
|
||||
)
|
||||
*glob.glob(os.path.dirname(sys.argv[0]) + '/[678][0-9]-*.hwdb'),
|
||||
])
|
||||
|
||||
for fname in args:
|
||||
groups = parse(fname)
|
||||
|
||||
@ -524,6 +524,18 @@
|
||||
<xi:include href="version-info.xml" xpointer="v252"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--efi-boot-option-description-with-device=</option></term>
|
||||
<listitem><para>Takes a boolean, defaults to false. Controls whether to append disk model information
|
||||
to the firmware boot option item description (as configured with
|
||||
<option>--efi-boot-option-description=</option> above). This is useful when installing multiple
|
||||
operating systems on separate disks on the same system, as it ensures the firmware boot options are discernable
|
||||
and give a hint which disk is booted into. Note that this uses hardware model information, and hence
|
||||
might not be too useful in case multiple disks of an identical model are used.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem><para>Dry run for <option>unlink</option> and <option>cleanup</option>.</para>
|
||||
|
||||
@ -1132,6 +1132,7 @@ manpages = [
|
||||
'ENABLE_RANDOMSEED'],
|
||||
['systemd-remount-fs.service', '8', ['systemd-remount-fs'], ''],
|
||||
['systemd-repart', '8', ['systemd-repart.service'], 'ENABLE_REPART'],
|
||||
['systemd-report', '1', [], ''],
|
||||
['systemd-resolved.service', '8', ['systemd-resolved'], 'ENABLE_RESOLVE'],
|
||||
['systemd-rfkill.service',
|
||||
'8',
|
||||
|
||||
74
man/systemd-report.xml
Normal file
74
man/systemd-report.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="systemd-report"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-report</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-report</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-report</refname>
|
||||
<refpurpose>Generate report of system facts and metrics</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>systemd-report</command> <arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-report</command> requests facts and metrics from the system and writes them to
|
||||
standard output.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--system</option></term>
|
||||
<term><option>--user</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Query per-system metrics sources (the default), or the per-user metrics sources.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit status</title>
|
||||
|
||||
<para>On success, 0 is returned, a non-zero failure code
|
||||
otherwise.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
@ -181,6 +181,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>list-registry</command></term>
|
||||
|
||||
<listitem><para>Shows a list of Varlink services currently registered in the service registry, plus
|
||||
their entrypoint sockets. (Currently, this simply enumerates the sockets and symlinked sockets in
|
||||
<filename>/run/varlink/registry/</filename>, see below.)</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>validate-idl</command> [<replaceable>FILE</replaceable>]</term>
|
||||
|
||||
@ -354,6 +364,18 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--system</option></term>
|
||||
<term><option>--user</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Determines whether to query to the per-system or per-user registry when using the
|
||||
<command>list-registry</command> command. By default, the per-system registry is queried.</para>
|
||||
</listitem>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="no-ask-password" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
@ -361,6 +383,31 @@
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Files & Directories</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><filename>/run/varlink/registry/</filename></term>
|
||||
|
||||
<listitem>
|
||||
<para>Directory containing <constant>AF_UNIX</constant> entrypoint socket inodes (or symlinks to
|
||||
them) of well-known, public Varlink interfaces on the local system. They are named after the
|
||||
Varlink interface they implement.</para>
|
||||
|
||||
<para>Use <command>varlinkctl list-registry</command> to show the contents of this
|
||||
directory.</para>
|
||||
|
||||
<para>(Inodes that neither qualify as socket inodes nor as symlinks to them shall be ignored. A
|
||||
future extension might introduce regular files and directories to enhance the registry
|
||||
functionality.)</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
install_data('70-systemd-shell-extra.sh', install_dir : shellprofiledir.startswith('/usr/') ? shellprofiledir : libexecdir / 'profile.d')
|
||||
install_data('80-systemd-osc-context.sh', install_dir : shellprofiledir.startswith('/usr/') ? shellprofiledir : libexecdir / 'profile.d')
|
||||
|
||||
if conf.get('LINK_SHELL_EXTRA_DROPIN') == 1
|
||||
if (not shellprofiledir.startswith(sysconfdir) or install_sysconfdir) and conf.get('LINK_SHELL_EXTRA_DROPIN') == 1
|
||||
if meson.version().version_compare('>=1.3.0')
|
||||
install_symlink(
|
||||
'70-systemd-shell-extra.sh',
|
||||
@ -19,7 +19,7 @@ if conf.get('LINK_SHELL_EXTRA_DROPIN') == 1
|
||||
endif
|
||||
endif
|
||||
|
||||
if conf.get('LINK_OSC_CONTEXT_DROPIN') == 1
|
||||
if (not shellprofiledir.startswith(sysconfdir) or install_sysconfdir) and conf.get('LINK_OSC_CONTEXT_DROPIN') == 1
|
||||
if meson.version().version_compare('>=1.3.0')
|
||||
install_symlink(
|
||||
'80-systemd-osc-context.sh',
|
||||
|
||||
@ -63,7 +63,7 @@ _varlinkctl() {
|
||||
fi
|
||||
|
||||
local -A VERBS=(
|
||||
[STANDALONE]='help'
|
||||
[STANDALONE]='help list-registry'
|
||||
[CALL]='call'
|
||||
[FILE]='info list-interfaces validate-idl'
|
||||
[ADDRESS_INTERFACES]='list-methods introspect'
|
||||
|
||||
@ -26,7 +26,10 @@
|
||||
CHASE_STEP | \
|
||||
CHASE_PROHIBIT_SYMLINKS | \
|
||||
CHASE_PARENT | \
|
||||
CHASE_MKDIR_0755)
|
||||
CHASE_MKDIR_0755 | \
|
||||
CHASE_MUST_BE_DIRECTORY | \
|
||||
CHASE_MUST_BE_REGULAR | \
|
||||
CHASE_MUST_BE_SOCKET)
|
||||
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b) {
|
||||
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
|
||||
@ -133,7 +136,6 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
|
||||
int r;
|
||||
|
||||
assert(!FLAGS_SET(flags, CHASE_PREFIX_ROOT));
|
||||
assert(!FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR));
|
||||
assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
|
||||
assert(!FLAGS_SET(flags, CHASE_NO_AUTOFS|CHASE_TRIGGER_AUTOFS));
|
||||
assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
|
||||
@ -328,6 +330,10 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
|
||||
if (FLAGS_SET(flags, CHASE_PARENT))
|
||||
flags |= CHASE_MUST_BE_DIRECTORY;
|
||||
|
||||
/* If multiple flags are set now, fail immediately */
|
||||
if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY) + FLAGS_SET(flags, CHASE_MUST_BE_REGULAR) + FLAGS_SET(flags, CHASE_MUST_BE_SOCKET) > 1)
|
||||
return -EBADSLT;
|
||||
|
||||
for (todo = buffer;;) {
|
||||
_cleanup_free_ char *first = NULL;
|
||||
_cleanup_close_ int child = -EBADF;
|
||||
@ -566,6 +572,12 @@ success:
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, CHASE_MUST_BE_SOCKET)) {
|
||||
r = stat_verify_socket(&st);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_path) {
|
||||
@ -872,7 +884,7 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
|
||||
DIR *d;
|
||||
int r;
|
||||
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR)));
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR|CHASE_MUST_BE_SOCKET)));
|
||||
assert(ret_dir);
|
||||
|
||||
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
|
||||
@ -970,7 +982,7 @@ int chase_and_fopen_unlocked(
|
||||
int mode_flags, r;
|
||||
|
||||
assert(path);
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT|CHASE_MUST_BE_DIRECTORY)));
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT|CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_SOCKET)));
|
||||
assert(open_flags);
|
||||
assert(ret_file);
|
||||
|
||||
@ -1040,7 +1052,7 @@ int chase_and_openat(
|
||||
_cleanup_free_ char *p = NULL, *fname = NULL;
|
||||
int r;
|
||||
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_SOCKET)));
|
||||
|
||||
XOpenFlags xopen_flags = 0;
|
||||
if (FLAGS_SET(chase_flags, CHASE_MUST_BE_DIRECTORY))
|
||||
@ -1086,7 +1098,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
|
||||
DIR *d;
|
||||
int r;
|
||||
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR)));
|
||||
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR|CHASE_MUST_BE_SOCKET)));
|
||||
assert(ret_dir);
|
||||
|
||||
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
|
||||
|
||||
@ -29,6 +29,7 @@ typedef enum ChaseFlags {
|
||||
CHASE_EXTRACT_FILENAME = 1 << 13, /* Only return the last component of the resolved path */
|
||||
CHASE_MUST_BE_DIRECTORY = 1 << 14, /* Fail if returned inode fd is not a dir */
|
||||
CHASE_MUST_BE_REGULAR = 1 << 15, /* Fail if returned inode fd is not a regular file */
|
||||
CHASE_MUST_BE_SOCKET = 1 << 16, /* Fail if returned inode fd is not a socket */
|
||||
} ChaseFlags;
|
||||
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b);
|
||||
|
||||
@ -5,10 +5,11 @@
|
||||
|
||||
#include "dirent-util.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int dirent_ensure_type(int dir_fd, struct dirent *de) {
|
||||
struct statx sx;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0);
|
||||
assert(de);
|
||||
@ -22,8 +23,16 @@ int dirent_ensure_type(int dir_fd, struct dirent *de) {
|
||||
}
|
||||
|
||||
/* Let's ask only for the type, nothing else. */
|
||||
if (statx(dir_fd, de->d_name, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT, STATX_TYPE, &sx) < 0)
|
||||
return -errno;
|
||||
struct statx sx;
|
||||
r = xstatx_full(dir_fd,
|
||||
de->d_name,
|
||||
AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT,
|
||||
/* mandatory_mask= */ STATX_TYPE,
|
||||
/* optional_mask= */ STATX_INO,
|
||||
/* mandatory_attributes= */ 0,
|
||||
&sx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(FLAGS_SET(sx.stx_mask, STATX_TYPE));
|
||||
de->d_type = IFTODT(sx.stx_mode);
|
||||
|
||||
@ -69,15 +69,14 @@ int make_lock_file_for(const char *p, int operation, LockFile *ret) {
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
r = path_extract_filename(p, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_directory(p, &dn);
|
||||
r = path_split_prefix_filename(p, &dn, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (dn)
|
||||
t = strjoin(dn, "/.#", fn, ".lck");
|
||||
else
|
||||
t = strjoin(".#", fn, ".lck");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@ -263,9 +263,14 @@ int is_mount_point_at(int dir_fd, const char *path, int flags) {
|
||||
/* When running on chroot environment, the root may not be a mount point, but we unconditionally
|
||||
* return true when the input is "/" in the above, but the shortcut may not work e.g. when the path
|
||||
* is relative. */
|
||||
struct statx sx2 = {}; /* explicitly initialize the struct to make msan silent. */
|
||||
if (statx(AT_FDCWD, "/", AT_STATX_DONT_SYNC, STATX_TYPE|STATX_INO, &sx2) < 0)
|
||||
return -errno;
|
||||
struct statx sx2;
|
||||
r = xstatx(AT_FDCWD,
|
||||
"/",
|
||||
AT_STATX_DONT_SYNC,
|
||||
STATX_TYPE|STATX_INO,
|
||||
&sx2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return statx_inode_same(&sx, &sx2);
|
||||
}
|
||||
|
||||
@ -1027,8 +1027,7 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char *
|
||||
q = path + strlen(path) - 1;
|
||||
|
||||
q = skip_slash_or_dot_backward(path, q);
|
||||
if (!q || /* the root directory */
|
||||
(q == path && *q == '.')) { /* path is "." or "./" */
|
||||
if (!q) { /* the root directory, "." or "./" */
|
||||
if (next)
|
||||
*next = path;
|
||||
if (ret)
|
||||
@ -1102,18 +1101,17 @@ const char* last_path_component(const char *path) {
|
||||
return path + k;
|
||||
}
|
||||
|
||||
int path_extract_filename(const char *path, char **ret) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
int path_split_prefix_filename(const char *path, char **ret_dir, char **ret_filename) {
|
||||
_cleanup_free_ char *d = NULL;
|
||||
const char *c, *next = NULL;
|
||||
int r;
|
||||
|
||||
/* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
|
||||
* filename_is_valid(). A wrapper around last_path_component(), but eats up trailing
|
||||
* slashes. Returns:
|
||||
/* Split the path into dir prefix/filename pair. Returns:
|
||||
*
|
||||
* -EINVAL → if the path is not valid
|
||||
* -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir
|
||||
* itself or "." is specified
|
||||
* -EADDRNOTAVAIL → if the path refers to the uppermost directory in hierarchy (i.e. has neither
|
||||
* dir prefix nor filename - the root dir itself or ".")
|
||||
* -EDESTADDRREQ → if only a filename was passed, and caller only specifies ret_dir
|
||||
* -ENOMEM → no memory
|
||||
*
|
||||
* Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to
|
||||
@ -1122,63 +1120,52 @@ int path_extract_filename(const char *path, char **ret) {
|
||||
* This function guarantees to return a fully valid filename, i.e. one that passes
|
||||
* filename_is_valid() – this means "." and ".." are not accepted. */
|
||||
|
||||
if (!path_is_valid(path))
|
||||
if (isempty(path))
|
||||
return -EINVAL;
|
||||
|
||||
r = path_find_last_component(path, false, &next, &c);
|
||||
r = path_find_last_component(path, /* accept_dot_dot = */ false, &next, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* root directory */
|
||||
if (r == 0) /* root directory or "." */
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
a = strndup(c, r);
|
||||
if (!a)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(a);
|
||||
return strlen(c) > (size_t) r ? O_DIRECTORY : 0;
|
||||
}
|
||||
|
||||
int path_extract_directory(const char *path, char **ret) {
|
||||
const char *c, *next = NULL;
|
||||
int r;
|
||||
|
||||
/* The inverse of path_extract_filename(), i.e. returns the directory path prefix. Returns:
|
||||
*
|
||||
* -EINVAL → if the path is not valid
|
||||
* -EDESTADDRREQ → if no directory was specified in the passed in path, i.e. only a filename was passed
|
||||
* -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e.
|
||||
* the root dir itself or "." was specified
|
||||
* -ENOMEM → no memory (surprise!)
|
||||
*
|
||||
* This function guarantees to return a fully valid path, i.e. one that passes path_is_valid().
|
||||
*/
|
||||
|
||||
r = path_find_last_component(path, false, &next, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* empty or root */
|
||||
return isempty(path) ? -EINVAL : -EADDRNOTAVAIL;
|
||||
if (ret_dir) {
|
||||
if (next == path) {
|
||||
if (*path != '/') /* filename only */
|
||||
if (*path != '/') { /* filename only */
|
||||
if (!ret_filename)
|
||||
return -EDESTADDRREQ;
|
||||
|
||||
return strdup_to(ret, "/");
|
||||
} else {
|
||||
d = strdup("/");
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *a = strndup(path, next - path);
|
||||
if (!a)
|
||||
} else {
|
||||
d = strndup(path, next - path);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
path_simplify(a);
|
||||
path_simplify(d);
|
||||
|
||||
if (!path_is_valid(a))
|
||||
if (!path_is_valid(d))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
} else if (!path_is_valid(path))
|
||||
/* We didn't validate the dir prefix, hence check if the whole path is valid now */
|
||||
return -EINVAL;
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(a);
|
||||
if (ret_filename) {
|
||||
char *fn = strndup(c, r);
|
||||
if (!fn)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
*ret_filename = fn;
|
||||
}
|
||||
|
||||
if (ret_dir)
|
||||
*ret_dir = TAKE_PTR(d);
|
||||
|
||||
return strlen(c) > (size_t) r ? O_DIRECTORY : 0;
|
||||
}
|
||||
|
||||
bool filename_part_is_valid(const char *p) {
|
||||
|
||||
@ -135,8 +135,15 @@ int fsck_exists_for_fstype(const char *fstype);
|
||||
int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret);
|
||||
int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret);
|
||||
const char* last_path_component(const char *path);
|
||||
int path_extract_filename(const char *path, char **ret);
|
||||
int path_extract_directory(const char *path, char **ret);
|
||||
|
||||
int path_split_prefix_filename(const char *path, char **ret_dir, char **ret_filename);
|
||||
static inline int path_extract_filename(const char *path, char **ret) {
|
||||
return path_split_prefix_filename(path, NULL, ret);
|
||||
}
|
||||
static inline int path_extract_directory(const char *path, char **ret) {
|
||||
int r = path_split_prefix_filename(path, ret, NULL);
|
||||
return r < 0 ? r : 0; /* suppress O_DIRECTORY */
|
||||
}
|
||||
|
||||
bool filename_part_is_valid(const char *p) _pure_;
|
||||
bool filename_is_valid(const char *p) _pure_;
|
||||
|
||||
@ -90,6 +90,21 @@ int stat_verify_directory(const struct stat *st) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int statx_verify_directory(const struct statx *stx) {
|
||||
assert(stx);
|
||||
|
||||
if (!FLAGS_SET(stx->stx_mask, STATX_TYPE))
|
||||
return -ENODATA;
|
||||
|
||||
if (S_ISLNK(stx->stx_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (!S_ISDIR(stx->stx_mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_verify_directory(int fd) {
|
||||
if (IN_SET(fd, AT_FDCWD, XAT_FDROOT))
|
||||
return 0;
|
||||
@ -127,6 +142,21 @@ int is_symlink(const char *path) {
|
||||
return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
|
||||
}
|
||||
|
||||
int stat_verify_socket(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
if (S_ISLNK(st->st_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return -EISDIR;
|
||||
|
||||
if (!S_ISSOCK(st->st_mode))
|
||||
return -ENOTSOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stat_verify_linked(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ int verify_regular_at(int fd, const char *path, bool follow);
|
||||
int fd_verify_regular(int fd);
|
||||
|
||||
int stat_verify_directory(const struct stat *st);
|
||||
int statx_verify_directory(const struct statx *stx);
|
||||
int fd_verify_directory(int fd);
|
||||
int is_dir_at(int fd, const char *path, bool follow);
|
||||
int is_dir(const char *path, bool follow);
|
||||
@ -19,6 +20,8 @@ int stat_verify_symlink(const struct stat *st);
|
||||
int fd_verify_symlink(int fd);
|
||||
int is_symlink(const char *path);
|
||||
|
||||
int stat_verify_socket(const struct stat *st);
|
||||
|
||||
int stat_verify_linked(const struct stat *st);
|
||||
int fd_verify_linked(int fd);
|
||||
|
||||
|
||||
@ -161,17 +161,12 @@ static int tempfn_build(const char *p, const char *pre, const char *post, bool c
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = path_extract_directory(p, &d);
|
||||
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
|
||||
return r;
|
||||
|
||||
r = path_extract_filename(p, &fn);
|
||||
r = path_split_prefix_filename(p, &d, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strlen(fn) > NAME_MAX - len_add)
|
||||
/* We cannot simply prepend and append strings to the filename. Let's truncate the filename. */
|
||||
fn[NAME_MAX - len_add] = '\0';
|
||||
/* Truncate the filename if it would become too long after mangling. */
|
||||
strshorten(fn, NAME_MAX - len_add);
|
||||
}
|
||||
|
||||
nf = strjoin(".#", strempty(pre), strempty(fn), strempty(post));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,10 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "shared-forward.h"
|
||||
|
||||
int verb_install(int argc, char *argv[], void *userdata);
|
||||
int verb_remove(int argc, char *argv[], void *userdata);
|
||||
int verb_is_installed(int argc, char *argv[], void *userdata);
|
||||
|
||||
int vl_method_install(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
|
||||
|
||||
@ -75,6 +75,8 @@ int get_file_version(int fd, char **ret) {
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
/* Does not reposition file offset (as it uses mmap()) */
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat EFI binary: %m");
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include "parse-argument.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
@ -39,12 +40,6 @@
|
||||
#include "verbs.h"
|
||||
#include "virt.h"
|
||||
|
||||
/* EFI_BOOT_OPTION_DESCRIPTION_MAX sets the maximum length for the boot option description
|
||||
* stored in NVRAM. The UEFI spec does not specify a minimum or maximum length for this
|
||||
* string, but we limit the length to something reasonable to prevent from the firmware
|
||||
* having to deal with a potentially too long string. */
|
||||
#define EFI_BOOT_OPTION_DESCRIPTION_MAX ((size_t) 255)
|
||||
|
||||
static GracefulMode _arg_graceful = ARG_GRACEFUL_NO;
|
||||
|
||||
char *arg_esp_path = NULL;
|
||||
@ -69,6 +64,7 @@ char *arg_root = NULL;
|
||||
char *arg_image = NULL;
|
||||
InstallSource arg_install_source = INSTALL_SOURCE_AUTO;
|
||||
char *arg_efi_boot_option_description = NULL;
|
||||
bool arg_efi_boot_option_description_with_device = false;
|
||||
bool arg_dry_run = false;
|
||||
ImagePolicy *arg_image_policy = NULL;
|
||||
bool arg_varlink = false;
|
||||
@ -93,6 +89,14 @@ STATIC_DESTRUCTOR_REGISTER(arg_certificate_source, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
|
||||
|
||||
static const char* const install_source_table[_INSTALL_SOURCE_MAX] = {
|
||||
[INSTALL_SOURCE_IMAGE] = "image",
|
||||
[INSTALL_SOURCE_HOST] = "host",
|
||||
[INSTALL_SOURCE_AUTO] = "auto",
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(install_source, InstallSource);
|
||||
|
||||
int acquire_esp(
|
||||
int unprivileged_mode,
|
||||
bool graceful,
|
||||
@ -340,6 +344,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" Install all supported EFI architectures\n"
|
||||
" --efi-boot-option-description=DESCRIPTION\n"
|
||||
" Description of the entry in the boot option list\n"
|
||||
" --efi-boot-option-description-with-device=yes\n"
|
||||
" Suffix description with disk vendor/model/serial\n"
|
||||
" --dry-run Dry run (unlink and cleanup)\n"
|
||||
" --secure-boot-auto-enroll=yes|no\n"
|
||||
" Set up secure boot auto-enrollment\n"
|
||||
@ -389,6 +395,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_JSON,
|
||||
ARG_ARCH_ALL,
|
||||
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
||||
ARG_EFI_BOOT_OPTION_DESCRIPTION_WITH_DEVICE,
|
||||
ARG_DRY_RUN,
|
||||
ARG_PRINT_LOADER_PATH,
|
||||
ARG_PRINT_STUB_PATH,
|
||||
@ -427,6 +434,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{ "all-architectures", no_argument, NULL, ARG_ARCH_ALL },
|
||||
{ "efi-boot-option-description", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION },
|
||||
{ "efi-boot-option-description-with-device", required_argument, NULL, ARG_EFI_BOOT_OPTION_DESCRIPTION_WITH_DEVICE },
|
||||
{ "dry-run", no_argument, NULL, ARG_DRY_RUN },
|
||||
{ "secure-boot-auto-enroll", required_argument, NULL, ARG_SECURE_BOOT_AUTO_ENROLL },
|
||||
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
|
||||
@ -481,18 +489,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_INSTALL_SOURCE:
|
||||
if (streq(optarg, "auto"))
|
||||
arg_install_source = INSTALL_SOURCE_AUTO;
|
||||
else if (streq(optarg, "image"))
|
||||
arg_install_source = INSTALL_SOURCE_IMAGE;
|
||||
else if (streq(optarg, "host"))
|
||||
arg_install_source = INSTALL_SOURCE_HOST;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unexpected parameter for --install-source=: %s", optarg);
|
||||
case ARG_INSTALL_SOURCE: {
|
||||
InstallSource is = install_source_from_string(optarg);
|
||||
if (is < 0)
|
||||
return log_error_errno(is, "Unexpected parameter for --install-source=: %s", optarg);
|
||||
|
||||
arg_install_source = is;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
arg_print_esp_path = true;
|
||||
@ -572,9 +576,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
case ARG_EFI_BOOT_OPTION_DESCRIPTION:
|
||||
if (isempty(optarg) || !(string_is_safe(optarg) && utf8_is_valid(optarg))) {
|
||||
_cleanup_free_ char *escaped = NULL;
|
||||
|
||||
escaped = cescape(optarg);
|
||||
_cleanup_free_ char *escaped = cescape(optarg);
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid --efi-boot-option-description=: %s", strna(escaped));
|
||||
}
|
||||
@ -587,6 +589,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_EFI_BOOT_OPTION_DESCRIPTION_WITH_DEVICE:
|
||||
r = parse_boolean_argument("--efi-boot-option-description-with-device=", optarg, &arg_efi_boot_option_description_with_device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case ARG_DRY_RUN:
|
||||
arg_dry_run = true;
|
||||
break;
|
||||
@ -711,7 +720,7 @@ static int vl_server(void) {
|
||||
|
||||
r = varlink_server_new(
|
||||
&varlink_server,
|
||||
SD_VARLINK_SERVER_ROOT_ONLY,
|
||||
SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT,
|
||||
/* userdata= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
||||
@ -724,7 +733,8 @@ static int vl_server(void) {
|
||||
varlink_server,
|
||||
"io.systemd.BootControl.ListBootEntries", vl_method_list_boot_entries,
|
||||
"io.systemd.BootControl.SetRebootToFirmware", vl_method_set_reboot_to_firmware,
|
||||
"io.systemd.BootControl.GetRebootToFirmware", vl_method_get_reboot_to_firmware);
|
||||
"io.systemd.BootControl.GetRebootToFirmware", vl_method_get_reboot_to_firmware,
|
||||
"io.systemd.BootControl.Install", vl_method_install);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to bind Varlink methods: %m");
|
||||
|
||||
|
||||
@ -37,6 +37,7 @@ extern char *arg_root;
|
||||
extern char *arg_image;
|
||||
extern InstallSource arg_install_source;
|
||||
extern char *arg_efi_boot_option_description;
|
||||
extern bool arg_efi_boot_option_description_with_device;
|
||||
extern bool arg_dry_run;
|
||||
extern ImagePolicy *arg_image_policy;
|
||||
extern bool arg_varlink;
|
||||
@ -59,3 +60,9 @@ int acquire_esp(int unprivileged_mode, bool graceful, uint32_t *ret_part, uint64
|
||||
int acquire_xbootldr(int unprivileged_mode, sd_id128_t *ret_uuid, dev_t *ret_devid);
|
||||
|
||||
bool touch_variables(void);
|
||||
|
||||
/* EFI_BOOT_OPTION_DESCRIPTION_MAX sets the maximum length for the boot option description
|
||||
* stored in NVRAM. The UEFI spec does not specify a minimum or maximum length for this
|
||||
* string, but we limit the length to something reasonable to prevent from the firmware
|
||||
* having to deal with a potentially too long string. */
|
||||
#define EFI_BOOT_OPTION_DESCRIPTION_MAX ((size_t) 255)
|
||||
|
||||
@ -328,6 +328,52 @@ void manager_process_native_message(
|
||||
} while (r == 0);
|
||||
}
|
||||
|
||||
static size_t entry_size_max_by_ucred(Manager *m, const struct ucred *ucred, const char *label) {
|
||||
static uint64_t entry_size_max = UINT64_MAX;
|
||||
static bool entry_size_max_checked = false;
|
||||
int r;
|
||||
|
||||
if (entry_size_max != UINT64_MAX)
|
||||
return entry_size_max;
|
||||
if (!entry_size_max_checked) {
|
||||
const char *p;
|
||||
|
||||
entry_size_max_checked = true;
|
||||
|
||||
p = secure_getenv("SYSTEMD_JOURNAL_FD_SIZE_MAX");
|
||||
if (p) {
|
||||
r = parse_size(p, 1024, &entry_size_max);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse $SYSTEMD_JOURNAL_FD_SIZE_MAX, ignoring: %m");
|
||||
else
|
||||
return entry_size_max;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for unprivileged senders, as the default limit of 768M is quite high and the socket is
|
||||
* unprivileged, to avoid abuses. */
|
||||
|
||||
if (!ucred)
|
||||
return ENTRY_SIZE_UNPRIV_MAX;
|
||||
if (ucred->uid == 0) /* Shortcut for root senders */
|
||||
return ENTRY_SIZE_MAX;
|
||||
|
||||
/* As an exception, allow coredumps to use the old max size for backward compatibility */
|
||||
if (pid_is_valid(ucred->pid)) {
|
||||
ClientContext *context = NULL;
|
||||
|
||||
r = client_context_get(m, ucred->pid, ucred, label, /* unit_id= */ NULL, &context);
|
||||
if (r < 0)
|
||||
log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
|
||||
"Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m",
|
||||
ucred->pid);
|
||||
else if (context->unit && startswith(context->unit, "systemd-coredump@"))
|
||||
return ENTRY_SIZE_MAX;
|
||||
}
|
||||
|
||||
return ENTRY_SIZE_UNPRIV_MAX;
|
||||
}
|
||||
|
||||
int manager_process_native_file(
|
||||
Manager *m,
|
||||
int fd,
|
||||
@ -392,7 +438,7 @@ int manager_process_native_file(
|
||||
|
||||
/* When !sealed, set a lower memory limit. We have to read the file, effectively doubling memory
|
||||
* use. */
|
||||
if (st.st_size > ENTRY_SIZE_MAX / (sealed ? 1 : 2))
|
||||
if ((size_t) st.st_size > entry_size_max_by_ucred(m, ucred, label) / (sealed ? 1 : 2))
|
||||
return log_ratelimit_error_errno(SYNTHETIC_ERRNO(EFBIG), JOURNAL_LOG_RATELIMIT,
|
||||
"File passed too large (%"PRIu64" bytes), refusing.",
|
||||
(uint64_t) st.st_size);
|
||||
|
||||
@ -51,12 +51,16 @@ static char *arg_root = NULL;
|
||||
static char *arg_image = NULL;
|
||||
static ImagePolicy *arg_image_policy = NULL;
|
||||
static bool arg_legend = true;
|
||||
static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
|
||||
static char *arg_entry_token = NULL;
|
||||
static BootEntryType arg_boot_entry_type = _BOOT_ENTRY_TYPE_INVALID;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
|
||||
|
||||
typedef enum Action {
|
||||
ACTION_ADD,
|
||||
@ -109,7 +113,15 @@ typedef struct Context {
|
||||
char **envp;
|
||||
} Context;
|
||||
|
||||
#define CONTEXT_NULL (Context) { .rfd = -EBADF }
|
||||
#define CONTEXT_NULL \
|
||||
(Context) { \
|
||||
.rfd = XAT_FDROOT, \
|
||||
.action = _ACTION_INVALID, \
|
||||
.kernel_image_type = _KERNEL_IMAGE_TYPE_INVALID, \
|
||||
.layout = _LAYOUT_INVALID, \
|
||||
.entry_type = _BOOT_ENTRY_TYPE_INVALID, \
|
||||
.entry_token_type = _BOOT_ENTRY_TOKEN_TYPE_INVALID, \
|
||||
}
|
||||
|
||||
static void context_done(Context *c) {
|
||||
assert(c);
|
||||
@ -429,20 +441,6 @@ static int context_set_initrds(Context *c, char* const* strv) {
|
||||
return context_set_path_strv(c, strv, "command line", "initrds", &c->initrds);
|
||||
}
|
||||
|
||||
static int context_set_entry_type(Context *c, const char *s) {
|
||||
assert(c);
|
||||
BootEntryType e;
|
||||
if (isempty(s) || streq(s, "all")) {
|
||||
c->entry_type = _BOOT_ENTRY_TYPE_INVALID;
|
||||
return 0;
|
||||
}
|
||||
e = boot_entry_type_from_string(s);
|
||||
if (e < 0)
|
||||
return log_error_errno(e, "Invalid entry type: %s", s);
|
||||
c->entry_type = e;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int context_load_environment(Context *c) {
|
||||
assert(c);
|
||||
|
||||
@ -695,11 +693,16 @@ static int context_load_plugins(Context *c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int context_init(Context *c) {
|
||||
static int context_setup(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (c->kernel_image_type < 0)
|
||||
c->kernel_image_type = KERNEL_IMAGE_TYPE_UNKNOWN;
|
||||
if (c->entry_token_type < 0)
|
||||
c->entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
|
||||
|
||||
r = context_open_root(c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -735,6 +738,24 @@ static int context_init(Context *c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int context_from_cmdline(Context *c, Action action) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
c->action = action;
|
||||
|
||||
c->entry_type = arg_boot_entry_type;
|
||||
|
||||
r = free_and_strdup_warn(&c->entry_token, arg_entry_token);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c->entry_token_type = arg_entry_token_type;
|
||||
|
||||
return context_setup(c);
|
||||
}
|
||||
|
||||
static int context_inspect_kernel(Context *c) {
|
||||
assert(c);
|
||||
|
||||
@ -768,9 +789,18 @@ static int context_ensure_layout(Context *c) {
|
||||
if (!srel_path)
|
||||
return log_oom();
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
r = chase_and_fopenat_unlocked(c->rfd, srel_path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to open '%s': %m", srel_path);
|
||||
} else {
|
||||
_cleanup_free_ char *srel = NULL;
|
||||
r = read_one_line_file_at(c->rfd, srel_path, &srel);
|
||||
if (r >= 0) {
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &srel);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read %s: %m", srel_path);
|
||||
|
||||
if (streq(srel, "type1"))
|
||||
/* The loader/entries.srel file clearly indicates that the installed boot loader
|
||||
* implements the proper standard upstream boot loader spec for Type #1 entries.
|
||||
@ -784,17 +814,17 @@ static int context_ensure_layout(Context *c) {
|
||||
|
||||
log_debug("%s with '%s' found, using layout=%s.", srel_path, srel, layout_to_string(c->layout));
|
||||
return 0;
|
||||
} else if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to read %s: %m", srel_path);
|
||||
}
|
||||
|
||||
_cleanup_free_ char *entry_token_path = path_join(c->boot_root, c->entry_token);
|
||||
if (!entry_token_path)
|
||||
return log_oom();
|
||||
|
||||
r = is_dir_at(c->rfd, entry_token_path, /* follow= */ false);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to check if '%s' is a directory: %m", entry_token_path);
|
||||
if (r > 0) {
|
||||
r = chaseat(c->rfd, entry_token_path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_DIRECTORY, /* ret_path= */ NULL, /* ret_fd= */ NULL);
|
||||
if (r < 0) {
|
||||
if (!IN_SET(r, -ENOENT, -ENOTDIR))
|
||||
return log_error_errno(r, "Failed to check if '%s' exists and is a directory: %m", entry_token_path);
|
||||
} else {
|
||||
/* If the metadata in $BOOT_ROOT doesn't tell us anything, then check if the entry token
|
||||
* directory already exists. If so, let's assume it's the standard boot loader spec, too. */
|
||||
c->layout = LAYOUT_BLS;
|
||||
@ -1091,6 +1121,26 @@ static bool bypass(void) {
|
||||
return should_bypass("KERNEL_INSTALL");
|
||||
}
|
||||
|
||||
static int kernel_from_version(const char *version, char **ret_kernel) {
|
||||
_cleanup_free_ char *vmlinuz = NULL;
|
||||
int r;
|
||||
|
||||
assert(version);
|
||||
|
||||
vmlinuz = path_join("/usr/lib/modules/", version, "/vmlinuz");
|
||||
if (!vmlinuz)
|
||||
return log_oom();
|
||||
|
||||
r = access_nofollow(vmlinuz, F_OK);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "Kernel image not installed to '%s', specify kernel kernel image path explicitly.", vmlinuz);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine if kernel image is installed to '%s': %m", vmlinuz);
|
||||
|
||||
*ret_kernel = TAKE_PTR(vmlinuz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_add(
|
||||
Context *c,
|
||||
const char *version,
|
||||
@ -1100,8 +1150,21 @@ static int do_add(
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(version);
|
||||
assert(kernel);
|
||||
|
||||
struct utsname un;
|
||||
if (!version) {
|
||||
assert_se(uname(&un) >= 0);
|
||||
version = un.release;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *vmlinuz = NULL;
|
||||
if (!kernel) {
|
||||
r = kernel_from_version(version, &vmlinuz);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
kernel = vmlinuz;
|
||||
}
|
||||
|
||||
r = context_set_version(c, version);
|
||||
if (r < 0)
|
||||
@ -1122,32 +1185,9 @@ static int do_add(
|
||||
return context_execute(c);
|
||||
}
|
||||
|
||||
static int kernel_from_version(const char *version, char **ret_kernel) {
|
||||
_cleanup_free_ char *vmlinuz = NULL;
|
||||
int r;
|
||||
|
||||
assert(version);
|
||||
|
||||
vmlinuz = path_join("/usr/lib/modules/", version, "/vmlinuz");
|
||||
if (!vmlinuz)
|
||||
return log_oom();
|
||||
|
||||
r = access_nofollow(vmlinuz, F_OK);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "Kernel image not installed to '%s', requiring manual kernel image path specification.", vmlinuz);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine if kernel image is installed to '%s': %m", vmlinuz);
|
||||
|
||||
*ret_kernel = TAKE_PTR(vmlinuz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_add(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ char *vmlinuz = NULL;
|
||||
const char *version, *kernel;
|
||||
char **initrds;
|
||||
struct utsname un;
|
||||
int r;
|
||||
|
||||
assert(argv);
|
||||
@ -1158,7 +1198,10 @@ static int verb_add(int argc, char *argv[], void *userdata) {
|
||||
if (bypass())
|
||||
return 0;
|
||||
|
||||
c->action = ACTION_ADD;
|
||||
_cleanup_(context_done) Context c = CONTEXT_NULL;
|
||||
r = context_from_cmdline(&c, ACTION_ADD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* We use the same order of arguments that "inspect" introduced, i.e. if only on argument is
|
||||
* specified we take it as the kernel path, not the version, i.e. it's the first argument that is
|
||||
@ -1168,24 +1211,10 @@ static int verb_add(int argc, char *argv[], void *userdata) {
|
||||
(argc > 1 ? empty_or_dash_to_null(argv[1]) : NULL);
|
||||
initrds = strv_skip(argv, 3);
|
||||
|
||||
if (!version) {
|
||||
assert_se(uname(&un) >= 0);
|
||||
version = un.release;
|
||||
}
|
||||
|
||||
if (!kernel) {
|
||||
r = kernel_from_version(version, &vmlinuz);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
kernel = vmlinuz;
|
||||
}
|
||||
|
||||
return do_add(c, version, kernel, initrds);
|
||||
return do_add(&c, version, kernel, initrds);
|
||||
}
|
||||
|
||||
static int verb_add_all(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
size_t n = 0;
|
||||
int ret = 0, r;
|
||||
@ -1198,9 +1227,12 @@ static int verb_add_all(int argc, char *argv[], void *userdata) {
|
||||
if (bypass())
|
||||
return 0;
|
||||
|
||||
c->action = ACTION_ADD;
|
||||
_cleanup_(context_done) Context c = CONTEXT_NULL;
|
||||
r = context_from_cmdline(&c, ACTION_ADD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = chase_and_openat(c->rfd, "/usr/lib/modules", CHASE_AT_RESOLVE_IN_ROOT, O_DIRECTORY|O_RDONLY|O_CLOEXEC, NULL);
|
||||
fd = chase_and_openat(c.rfd, "/usr/lib/modules", CHASE_AT_RESOLVE_IN_ROOT, O_DIRECTORY|O_RDONLY|O_CLOEXEC, NULL);
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to open %s/usr/lib/modules/: %m", strempty(arg_root));
|
||||
|
||||
@ -1234,7 +1266,7 @@ static int verb_add_all(int argc, char *argv[], void *userdata) {
|
||||
|
||||
_cleanup_(context_done) Context copy = CONTEXT_NULL;
|
||||
|
||||
r = context_copy(c, ©);
|
||||
r = context_copy(&c, ©);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to copy execution context: %m");
|
||||
|
||||
@ -1262,18 +1294,17 @@ static int verb_add_all(int argc, char *argv[], void *userdata) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int run_as_installkernel(int argc, char *argv[], Context *c) {
|
||||
static int run_as_installkernel(int argc, char *argv[]) {
|
||||
/* kernel's install.sh invokes us as
|
||||
* /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
|
||||
* We ignore the last two arguments. */
|
||||
if (optind + 2 > argc)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "'installkernel' command requires at least two arguments.");
|
||||
|
||||
return verb_add(3, STRV_MAKE("add", argv[optind], argv[optind+1]), c);
|
||||
return verb_add(3, STRV_MAKE("add", argv[optind], argv[optind+1]), /* userdata= */ NULL);
|
||||
}
|
||||
|
||||
static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(argc >= 2);
|
||||
@ -1289,25 +1320,27 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
if (bypass())
|
||||
return 0;
|
||||
|
||||
c->action = ACTION_REMOVE;
|
||||
_cleanup_(context_done) Context c = CONTEXT_NULL;
|
||||
r = context_from_cmdline(&c, ACTION_REMOVE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Note, we do not automatically derive the kernel version to remove from uname() here (unlike we do
|
||||
* it for the "add" verb), since we don't want to make it too easy to uninstall your running
|
||||
* kernel, as a safety precaution */
|
||||
|
||||
r = context_set_version(c, argv[1]);
|
||||
r = context_set_version(&c, argv[1]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = context_prepare_execution(c);
|
||||
r = context_prepare_execution(&c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return context_execute(c);
|
||||
return context_execute(&c);
|
||||
}
|
||||
|
||||
static int verb_inspect(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
_cleanup_(table_unrefp) Table *t = NULL;
|
||||
_cleanup_free_ char *vmlinuz = NULL;
|
||||
const char *version, *kernel;
|
||||
@ -1315,7 +1348,10 @@ static int verb_inspect(int argc, char *argv[], void *userdata) {
|
||||
struct utsname un;
|
||||
int r;
|
||||
|
||||
c->action = ACTION_INSPECT;
|
||||
_cleanup_(context_done) Context c = CONTEXT_NULL;
|
||||
r = context_from_cmdline(&c, ACTION_INSPECT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* When only a single parameter is specified 'inspect' it's the kernel image path, and not the kernel
|
||||
* version. i.e. it's the first argument that is optional, not the 2nd. That's a bit unfortunate, but
|
||||
@ -1340,19 +1376,19 @@ static int verb_inspect(int argc, char *argv[], void *userdata) {
|
||||
kernel = vmlinuz;
|
||||
}
|
||||
|
||||
r = context_set_version(c, version);
|
||||
r = context_set_version(&c, version);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = context_set_kernel(c, kernel);
|
||||
r = context_set_kernel(&c, kernel);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = context_set_initrds(c, initrds);
|
||||
r = context_set_initrds(&c, initrds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = context_prepare_execution(c);
|
||||
r = context_prepare_execution(&c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1362,40 +1398,40 @@ static int verb_inspect(int argc, char *argv[], void *userdata) {
|
||||
|
||||
r = table_add_many(t,
|
||||
TABLE_FIELD, "Machine ID",
|
||||
TABLE_ID128, c->machine_id,
|
||||
TABLE_ID128, c.machine_id,
|
||||
TABLE_FIELD, "Kernel Image Type",
|
||||
TABLE_STRING, kernel_image_type_to_string(c->kernel_image_type),
|
||||
TABLE_STRING, kernel_image_type_to_string(c.kernel_image_type),
|
||||
TABLE_FIELD, "Layout",
|
||||
TABLE_STRING, context_get_layout(c),
|
||||
TABLE_STRING, context_get_layout(&c),
|
||||
TABLE_FIELD, "Boot Root",
|
||||
TABLE_STRING, c->boot_root,
|
||||
TABLE_STRING, c.boot_root,
|
||||
TABLE_FIELD, "Entry Token Type",
|
||||
TABLE_STRING, boot_entry_token_type_to_string(c->entry_token_type),
|
||||
TABLE_STRING, boot_entry_token_type_to_string(c.entry_token_type),
|
||||
TABLE_FIELD, "Entry Token",
|
||||
TABLE_STRING, c->entry_token,
|
||||
TABLE_STRING, c.entry_token,
|
||||
TABLE_FIELD, "Entry Directory",
|
||||
TABLE_STRING, c->entry_dir,
|
||||
TABLE_STRING, c.entry_dir,
|
||||
TABLE_FIELD, "Kernel Version",
|
||||
TABLE_VERSION, c->version,
|
||||
TABLE_VERSION, c.version,
|
||||
TABLE_FIELD, "Kernel",
|
||||
TABLE_STRING, c->kernel,
|
||||
TABLE_STRING, c.kernel,
|
||||
TABLE_FIELD, "Initrds",
|
||||
TABLE_STRV, c->initrds,
|
||||
TABLE_STRV, c.initrds,
|
||||
TABLE_FIELD, "Initrd Generator",
|
||||
TABLE_STRING, c->initrd_generator,
|
||||
TABLE_STRING, c.initrd_generator,
|
||||
TABLE_FIELD, "UKI Generator",
|
||||
TABLE_STRING, c->uki_generator,
|
||||
TABLE_STRING, c.uki_generator,
|
||||
TABLE_FIELD, "Plugins",
|
||||
TABLE_STRV, c->plugins,
|
||||
TABLE_STRV, c.plugins,
|
||||
TABLE_FIELD, "Plugin Environment",
|
||||
TABLE_STRV, c->envp);
|
||||
TABLE_STRV, c.envp);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
if (!sd_json_format_enabled(arg_json_format_flags)) {
|
||||
r = table_add_many(t,
|
||||
TABLE_FIELD, "Plugin Arguments",
|
||||
TABLE_STRV, strv_skip(c->argv, 1));
|
||||
TABLE_STRV, strv_skip(c.argv, 1));
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
@ -1418,11 +1454,15 @@ static int verb_inspect(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
static int verb_list(int argc, char *argv[], void *userdata) {
|
||||
Context *c = ASSERT_PTR(userdata);
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
fd = chase_and_openat(c->rfd, "/usr/lib/modules", CHASE_AT_RESOLVE_IN_ROOT, O_DIRECTORY|O_RDONLY|O_CLOEXEC, NULL);
|
||||
_cleanup_(context_done) Context c = CONTEXT_NULL;
|
||||
r = context_from_cmdline(&c, ACTION_INSPECT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = chase_and_openat(c.rfd, "/usr/lib/modules", CHASE_AT_RESOLVE_IN_ROOT, O_DIRECTORY|O_RDONLY|O_CLOEXEC, NULL);
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to open %s/usr/lib/modules/: %m", strempty(arg_root));
|
||||
|
||||
@ -1532,7 +1572,7 @@ static int help(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_argv(int argc, char *argv[], Context *c) {
|
||||
static int parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_NO_LEGEND,
|
||||
@ -1568,7 +1608,6 @@ static int parse_argv(int argc, char *argv[], Context *c) {
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
assert(c);
|
||||
|
||||
while ((t = getopt_long(argc, argv, "hv", options, NULL)) >= 0)
|
||||
switch (t) {
|
||||
@ -1612,7 +1651,7 @@ static int parse_argv(int argc, char *argv[], Context *c) {
|
||||
break;
|
||||
|
||||
case ARG_ENTRY_TOKEN:
|
||||
r = parse_boot_entry_token_type(optarg, &c->entry_token_type, &c->entry_token);
|
||||
r = parse_boot_entry_token_type(optarg, &arg_entry_token_type, &arg_entry_token);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
@ -1645,11 +1684,18 @@ static int parse_argv(int argc, char *argv[], Context *c) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_BOOT_ENTRY_TYPE:
|
||||
r = context_set_entry_type(c, optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
case ARG_BOOT_ENTRY_TYPE: {
|
||||
if (isempty(optarg) || streq(optarg, "all")) {
|
||||
arg_boot_entry_type = _BOOT_ENTRY_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
BootEntryType e = boot_entry_type_from_string(optarg);
|
||||
if (e < 0)
|
||||
return log_error_errno(e, "Invalid entry type: %s", optarg);
|
||||
arg_boot_entry_type = e;
|
||||
break;
|
||||
}
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
@ -1664,7 +1710,7 @@ static int parse_argv(int argc, char *argv[], Context *c) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int run(int argc, char* argv[]) {
|
||||
static int kernel_install_main(int argc, char *argv[]) {
|
||||
static const Verb verbs[] = {
|
||||
{ "add", 1, VERB_ANY, 0, verb_add },
|
||||
{ "add-all", 1, 1, 0, verb_add_all },
|
||||
@ -1673,24 +1719,21 @@ static int run(int argc, char* argv[]) {
|
||||
{ "list", 1, 1, 0, verb_list },
|
||||
{}
|
||||
};
|
||||
_cleanup_(context_done) Context c = {
|
||||
.rfd = AT_FDCWD,
|
||||
.action = _ACTION_INVALID,
|
||||
.kernel_image_type = KERNEL_IMAGE_TYPE_UNKNOWN,
|
||||
.layout = _LAYOUT_INVALID,
|
||||
.entry_type = _BOOT_ENTRY_TYPE_INVALID,
|
||||
.entry_token_type = BOOT_ENTRY_TOKEN_AUTO,
|
||||
};
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
|
||||
|
||||
return dispatch_verb(argc, argv, verbs, /* userdata= */ NULL);
|
||||
}
|
||||
|
||||
static int run(int argc, char* argv[]) {
|
||||
int r;
|
||||
|
||||
log_setup();
|
||||
|
||||
r = parse_argv(argc, argv, &c);
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
|
||||
if (arg_image) {
|
||||
assert(!arg_root);
|
||||
|
||||
@ -1713,14 +1756,10 @@ static int run(int argc, char* argv[]) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = context_init(&c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (invoked_as(argv, "installkernel"))
|
||||
return run_as_installkernel(argc, argv, &c);
|
||||
return run_as_installkernel(argc, argv);
|
||||
|
||||
return dispatch_verb(argc, argv, verbs, &c);
|
||||
return kernel_install_main(argc, argv);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|
||||
|
||||
@ -387,6 +387,19 @@ _public_ int sd_journal_stream_fd_with_namespace(
|
||||
assert_return(priority >= 0, -EINVAL);
|
||||
assert_return(priority <= 7, -EINVAL);
|
||||
|
||||
if (name_space) {
|
||||
/* If $LOG_NAMESPACE is set, we're already placed in a mountns with /run/systemd/journal/
|
||||
* being a bind mount for the journald namespace instance, in which case we shall go by
|
||||
* the standard journal socket path. */
|
||||
const char *env = secure_getenv("LOG_NAMESPACE");
|
||||
if (env) {
|
||||
if (!streq(name_space, env))
|
||||
return -EREMOTE;
|
||||
|
||||
name_space = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
path = journal_stream_path(name_space);
|
||||
if (!path)
|
||||
return -EINVAL;
|
||||
|
||||
@ -801,11 +801,18 @@ static DirectoryOwnership validate_directory_fd(
|
||||
* check if the directory is owned by the peer UID or by the foreign UID range (in the latter case
|
||||
* one of the parent directories must be owned by the peer though). */
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_debug_errno(errno, "Failed to stat() directory fd: %m");
|
||||
struct statx stx;
|
||||
r = xstatx_full(fd,
|
||||
/* path= */ NULL,
|
||||
AT_EMPTY_PATH,
|
||||
/* mandatory_mask= */ STATX_TYPE|STATX_UID|STATX_MNT_ID|STATX_INO,
|
||||
/* optional_mask= */ 0,
|
||||
/* mandatory_attributes= */ STATX_ATTR_MOUNT_ROOT,
|
||||
&stx);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to statx() directory fd: %m");
|
||||
|
||||
r = stat_verify_directory(&st);
|
||||
r = statx_verify_directory(&stx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -813,8 +820,8 @@ static DirectoryOwnership validate_directory_fd(
|
||||
if (fl < 0)
|
||||
return log_debug_errno(fl, "Directory file descriptor has unsafe flags set: %m");
|
||||
|
||||
if (st.st_uid == 0) {
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
if (stx.stx_uid == 0) {
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
if (peer_uid == 0) {
|
||||
log_debug("Directory file descriptor points to root owned directory (%s), who is also the peer.", strna(path));
|
||||
return DIRECTORY_IS_ROOT_PEER_OWNED;
|
||||
@ -822,9 +829,9 @@ static DirectoryOwnership validate_directory_fd(
|
||||
log_debug("Directory file descriptor points to root owned directory (%s).", strna(path));
|
||||
return DIRECTORY_IS_ROOT_OWNED;
|
||||
}
|
||||
if (st.st_uid == peer_uid) {
|
||||
if (stx.stx_uid == peer_uid) {
|
||||
log_debug("Directory file descriptor points to peer owned directory (%s).", strna(path));
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_PEER_OWNED;
|
||||
}
|
||||
|
||||
@ -835,17 +842,24 @@ static DirectoryOwnership validate_directory_fd(
|
||||
_cleanup_close_ int parent_fd = -EBADF;
|
||||
unsigned n_level;
|
||||
for (n_level = 0; n_level < 16; n_level++) {
|
||||
/* Do not go above bind mounts */
|
||||
if (FLAGS_SET(stx.stx_attributes, STATX_ATTR_MOUNT_ROOT)) {
|
||||
log_debug("Directory is a mount point, not checking for parent's ownership.");
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_OTHERWISE_OWNED;
|
||||
}
|
||||
|
||||
/* Stop iteration if we find a directory up the tree that is neither owned by the user, nor is from the foreign UID range */
|
||||
if (!uid_is_foreign(st.st_uid) || !gid_is_foreign(st.st_gid)) {
|
||||
if (!uid_is_foreign(stx.stx_uid) || !gid_is_foreign(stx.stx_gid)) {
|
||||
log_debug("Directory file descriptor points to directory which itself or its parents is neither owned by foreign UID range nor by the user.");
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_OTHERWISE_OWNED;
|
||||
}
|
||||
|
||||
/* If the peer is root, then it doesn't matter if we find a parent owned by root, let's shortcut things. */
|
||||
if (peer_uid == 0) {
|
||||
log_debug("Directory referenced by file descriptor is owned by foreign UID range, and peer is root.");
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_FOREIGN_OWNED;
|
||||
}
|
||||
|
||||
@ -854,29 +868,46 @@ static DirectoryOwnership validate_directory_fd(
|
||||
if (new_parent_fd < 0)
|
||||
return log_debug_errno(errno, "Failed to open parent directory of directory file descriptor: %m");
|
||||
|
||||
struct stat new_st;
|
||||
if (fstat(new_parent_fd, &new_st) < 0)
|
||||
return log_debug_errno(errno, "Failed to stat parent directory of directory file descriptor: %m");
|
||||
struct statx new_stx;
|
||||
r = xstatx_full(new_parent_fd,
|
||||
/* path= */ NULL,
|
||||
AT_EMPTY_PATH,
|
||||
/* mandatory_mask= */ STATX_UID|STATX_MNT_ID|STATX_INO,
|
||||
/* optional_mask= */ 0,
|
||||
/* mandatory_attributes= */ STATX_ATTR_MOUNT_ROOT,
|
||||
&new_stx);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to statx() parent directory of directory file descriptor: %m");
|
||||
|
||||
/* Safety check to see if we hit the root dir */
|
||||
if (stat_inode_same(&st, &new_st)) {
|
||||
if (statx_inode_same(&stx, &new_stx)) {
|
||||
log_debug("Directory file descriptor is owned by foreign UID range, but didn't find parent directory that is owned by peer among ancestors.");
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_OTHERWISE_OWNED;
|
||||
}
|
||||
|
||||
if (new_st.st_uid == peer_uid) { /* Parent inode is owned by the peer. That's good! Everything's fine. */
|
||||
if (stx.stx_mnt_id != new_stx.stx_mnt_id) {
|
||||
/* NB, this check is probably redundant, given we also check
|
||||
* STATX_ATTR_MOUNT_ROOT. The only reason we have it here is to provide extra safety
|
||||
* in case the mount tree is rearranged concurrently with our traversal, so that
|
||||
* STATX_ATTR_MOUNT_ROOT might be out of date. */
|
||||
log_debug("Won't cross mount boundaries, not checking for parent's ownership.");
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_OTHERWISE_OWNED;
|
||||
}
|
||||
|
||||
if (new_stx.stx_uid == peer_uid) { /* Parent inode is owned by the peer. That's good! Everything's fine. */
|
||||
log_debug("Directory file descriptor is owned by foreign UID range, and ancestor is owned by peer.");
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_FOREIGN_OWNED;
|
||||
}
|
||||
|
||||
close_and_replace(parent_fd, new_parent_fd);
|
||||
st = new_st;
|
||||
stx = new_stx;
|
||||
}
|
||||
|
||||
log_debug("Failed to find peer owned parent directory after %u levels, refusing.", n_level);
|
||||
*ret_current_owner_uid = st.st_uid;
|
||||
*ret_current_owner_uid = stx.stx_uid;
|
||||
return DIRECTORY_IS_OTHERWISE_OWNED;
|
||||
}
|
||||
|
||||
|
||||
@ -12,22 +12,28 @@
|
||||
#include "fd-util.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "parse-argument.h"
|
||||
#include "path-lookup.h"
|
||||
#include "pretty-print.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "set.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
#include "varlink-util.h"
|
||||
|
||||
#define MAX_CONCURRENT_METRICS_SOCKETS 20
|
||||
#define METRICS_MAX 1024U
|
||||
#define METRICS_LINKS_MAX 128U
|
||||
#define TIMEOUT_USEC (30 * USEC_PER_SEC) /* 30 seconds */
|
||||
|
||||
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
|
||||
|
||||
typedef struct Context {
|
||||
unsigned n_open_connections;
|
||||
sd_event *event;
|
||||
Set *links;
|
||||
sd_json_variant **metrics; /* Collected metrics for sorting */
|
||||
size_t n_metrics;
|
||||
size_t n_metrics, n_skipped_metrics;
|
||||
} Context;
|
||||
|
||||
static int metric_compare(sd_json_variant *const *a, sd_json_variant *const *b) {
|
||||
@ -80,6 +86,11 @@ static int metrics_on_query_reply(
|
||||
else
|
||||
log_error("Varlink error: %s", error_id);
|
||||
} else {
|
||||
if (context->n_metrics >= METRICS_MAX) {
|
||||
context->n_skipped_metrics++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Collect metrics for later sorting */
|
||||
if (!GREEDY_REALLOC(context->metrics, context->n_metrics + 1))
|
||||
return log_oom();
|
||||
@ -87,24 +98,22 @@ static int metrics_on_query_reply(
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(flags, SD_VARLINK_REPLY_CONTINUES)) {
|
||||
assert(context->n_open_connections > 0);
|
||||
context->n_open_connections--;
|
||||
assert_se(set_remove(context->links, link) == link);
|
||||
link = sd_varlink_close_unref(link);
|
||||
|
||||
if (context->n_open_connections == 0)
|
||||
(void) sd_event_exit(ASSERT_PTR(sd_varlink_get_event(link)), EXIT_SUCCESS);
|
||||
if (set_isempty(context->links))
|
||||
(void) sd_event_exit(context->event, EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int metrics_call(const char *path, sd_event *event, sd_varlink **ret, Context *context) {
|
||||
static int metrics_call(Context *context, const char *path) {
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(event);
|
||||
assert(ret);
|
||||
assert(context);
|
||||
assert(path);
|
||||
|
||||
r = sd_varlink_connect_address(&vl, path);
|
||||
if (r < 0)
|
||||
@ -116,7 +125,7 @@ static int metrics_call(const char *path, sd_event *event, sd_varlink **ret, Con
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set varlink timeout: %m");
|
||||
|
||||
r = sd_varlink_attach_event(vl, event, SD_EVENT_PRIORITY_NORMAL);
|
||||
r = sd_varlink_attach_event(vl, context->event, SD_EVENT_PRIORITY_NORMAL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
|
||||
|
||||
@ -128,42 +137,42 @@ static int metrics_call(const char *path, sd_event *event, sd_varlink **ret, Con
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to issue io.systemd.Metrics.List call: %m");
|
||||
|
||||
*ret = TAKE_PTR(vl);
|
||||
if (set_ensure_put(&context->links, &varlink_hash_ops, vl) < 0)
|
||||
return log_oom();
|
||||
|
||||
TAKE_PTR(vl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sd_varlink_unref_many(sd_varlink **array, size_t n) {
|
||||
assert(array);
|
||||
|
||||
FOREACH_ARRAY(v, array, n)
|
||||
sd_varlink_unref(*v);
|
||||
|
||||
free(array);
|
||||
}
|
||||
|
||||
static void context_done(Context *context) {
|
||||
assert(context);
|
||||
|
||||
for (size_t i = 0; i < context->n_metrics; i++)
|
||||
sd_json_variant_unref(context->metrics[i]);
|
||||
free(context->metrics);
|
||||
set_free(context->links);
|
||||
sd_json_variant_unref_many(context->metrics, context->n_metrics);
|
||||
sd_event_unref(context->event);
|
||||
}
|
||||
|
||||
static void metrics_output_sorted(Context *context) {
|
||||
static int metrics_output_sorted(Context *context) {
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
|
||||
typesafe_qsort(context->metrics, context->n_metrics, metric_compare);
|
||||
|
||||
FOREACH_ARRAY(m, context->metrics, context->n_metrics)
|
||||
sd_json_variant_dump(
|
||||
FOREACH_ARRAY(m, context->metrics, context->n_metrics) {
|
||||
r = sd_json_variant_dump(
|
||||
*m,
|
||||
SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO | SD_JSON_FORMAT_FLUSH,
|
||||
arg_json_format_flags | SD_JSON_FORMAT_FLUSH,
|
||||
stdout,
|
||||
NULL);
|
||||
/* prefix= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write JSON: %m");
|
||||
}
|
||||
|
||||
if (context->n_metrics == 0)
|
||||
log_warning("No reporting sockets found.");
|
||||
log_info("No metrics collected.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int metrics_query(void) {
|
||||
@ -176,58 +185,63 @@ static int metrics_query(void) {
|
||||
|
||||
log_debug("Looking for reports in %s/", metrics_path);
|
||||
|
||||
_cleanup_closedir_ DIR *d = opendir(metrics_path);
|
||||
if (!d)
|
||||
return log_full_errno(errno == ENOENT ? LOG_WARNING : LOG_ERR, errno,
|
||||
"Failed to open metrics directory %s: %m", metrics_path);
|
||||
_cleanup_(context_done) Context context = {};
|
||||
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
r = sd_event_default(&event);
|
||||
r = sd_event_default(&context.event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get event loop: %m");
|
||||
|
||||
r = sd_event_set_signal_exit(event, true);
|
||||
r = sd_event_set_signal_exit(context.event, true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable exit on SIGINT/SIGTERM: %m");
|
||||
|
||||
size_t n_varlinks = MAX_CONCURRENT_METRICS_SOCKETS;
|
||||
sd_varlink **varlinks = new0(sd_varlink *, n_varlinks);
|
||||
if (!varlinks)
|
||||
return log_oom();
|
||||
|
||||
CLEANUP_ARRAY(varlinks, n_varlinks, sd_varlink_unref_many);
|
||||
|
||||
_cleanup_(context_done) Context context = {};
|
||||
|
||||
size_t n_skipped_sources = 0;
|
||||
_cleanup_closedir_ DIR *d = opendir(metrics_path);
|
||||
if (!d) {
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to open metrics directory %s: %m", metrics_path);
|
||||
} else {
|
||||
FOREACH_DIRENT(de, d,
|
||||
return log_warning_errno(errno, "Failed to read %s: %m", metrics_path)) {
|
||||
|
||||
if (!IN_SET(de->d_type, DT_SOCK, DT_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (set_size(context.links) >= METRICS_LINKS_MAX) {
|
||||
n_skipped_sources++;
|
||||
break;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *p = path_join(metrics_path, de->d_name);
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
r = metrics_call(p, event, &varlinks[context.n_open_connections], &context);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
if (++context.n_open_connections >= MAX_CONCURRENT_METRICS_SOCKETS) {
|
||||
log_warning("Too many concurrent metrics sockets, stop iterating");
|
||||
break;
|
||||
(void) metrics_call(&context, p);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.n_open_connections > 0) {
|
||||
r = sd_event_loop(event);
|
||||
if (set_isempty(context.links))
|
||||
log_info("No metrics sources found.");
|
||||
else {
|
||||
r = sd_event_loop(context.event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to run event loop: %m");
|
||||
|
||||
r = metrics_output_sorted(&context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (n_skipped_sources > 0)
|
||||
log_warning("Too many metrics sources, only %u sources contacted, %zu sources skipped.", set_size(context.links), n_skipped_sources);
|
||||
if (context.n_skipped_metrics > 0)
|
||||
log_warning("Too many metrics, only %zu metrics collected, %zu metrics skipped.", context.n_metrics, context.n_skipped_metrics);
|
||||
|
||||
if (n_skipped_sources > 0 ||
|
||||
context.n_skipped_metrics > 0)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
metrics_output_sorted(&context);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
@ -244,6 +258,8 @@ static int help(void) {
|
||||
" --version Show package version\n"
|
||||
" --user Connect to user service manager\n"
|
||||
" --system Connect to system service manager (default)\n"
|
||||
" --json=pretty|short\n"
|
||||
" Configure JSON output\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
@ -258,6 +274,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_USER,
|
||||
ARG_SYSTEM,
|
||||
ARG_JSON,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -265,28 +282,41 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "user", no_argument, NULL, ARG_USER },
|
||||
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{}
|
||||
};
|
||||
|
||||
int c;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hp", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
switch (c) {
|
||||
case 'h':
|
||||
return help();
|
||||
|
||||
case ARG_VERSION:
|
||||
return version();
|
||||
|
||||
case ARG_USER:
|
||||
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
||||
break;
|
||||
|
||||
case ARG_SYSTEM:
|
||||
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
case ARG_JSON:
|
||||
r = parse_json_argument(optarg, &arg_json_format_flags);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
@ -922,6 +922,7 @@ int blockdev_get_root(int level, dev_t *ret) {
|
||||
}
|
||||
|
||||
int partition_node_of(const char *node, unsigned nr, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL, *dn = NULL;
|
||||
int r;
|
||||
|
||||
assert(node);
|
||||
@ -931,18 +932,12 @@ int partition_node_of(const char *node, unsigned nr, char **ret) {
|
||||
/* Given a device node path to a block device returns the device node path to the partition block
|
||||
* device of the specified partition */
|
||||
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
r = path_extract_filename(node, &fn);
|
||||
r = path_split_prefix_filename(node, &dn, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EISDIR;
|
||||
|
||||
_cleanup_free_ char *dn = NULL;
|
||||
r = path_extract_directory(node, &dn);
|
||||
if (r < 0 && r != -EDESTADDRREQ) /* allow if only filename is specified */
|
||||
return r;
|
||||
|
||||
size_t l = strlen(fn);
|
||||
assert(l > 0); /* underflow check for the subtraction below */
|
||||
|
||||
|
||||
@ -155,6 +155,8 @@ int boot_entry_token_ensure_at(
|
||||
assert(type);
|
||||
assert(token);
|
||||
|
||||
/* Returns -EUNATCH if the selected token is not set */
|
||||
|
||||
if (*token)
|
||||
return 0; /* Already set. */
|
||||
|
||||
@ -181,7 +183,7 @@ int boot_entry_token_ensure_at(
|
||||
return r;
|
||||
}
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUNATCH),
|
||||
"No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
|
||||
|
||||
case BOOT_ENTRY_TOKEN_MACHINE_ID:
|
||||
@ -189,14 +191,14 @@ int boot_entry_token_ensure_at(
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set.");
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUNATCH), "No machine ID set.");
|
||||
|
||||
case BOOT_ENTRY_TOKEN_OS_IMAGE_ID:
|
||||
r = entry_token_from_os_release(rfd, type, token);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUNATCH),
|
||||
"IMAGE_ID= field not set in /etc/os-release.");
|
||||
|
||||
case BOOT_ENTRY_TOKEN_OS_ID:
|
||||
@ -204,12 +206,12 @@ int boot_entry_token_ensure_at(
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUNATCH),
|
||||
"ID= field not set in /etc/os-release.");
|
||||
|
||||
case BOOT_ENTRY_TOKEN_LITERAL:
|
||||
/* In this case, the token should be already set by the user input. */
|
||||
return -EINVAL;
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EUNATCH), "Literal token indicated but not specified.");
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
@ -291,4 +293,4 @@ static const char *const boot_entry_token_type_table[] = {
|
||||
[BOOT_ENTRY_TOKEN_AUTO] = "auto",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_token_type, BootEntryTokenType);
|
||||
DEFINE_STRING_TABLE_LOOKUP(boot_entry_token_type, BootEntryTokenType);
|
||||
|
||||
@ -34,4 +34,4 @@ int boot_entry_token_ensure_at(
|
||||
|
||||
int parse_boot_entry_token_type(const char *s, BootEntryTokenType *type, char **token);
|
||||
|
||||
DECLARE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_token_type, BootEntryTokenType);
|
||||
DECLARE_STRING_TABLE_LOOKUP(boot_entry_token_type, BootEntryTokenType);
|
||||
|
||||
@ -480,14 +480,13 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
|
||||
if (!path_is_absolute(e))
|
||||
return -EINVAL;
|
||||
|
||||
r = path_extract_directory(e, &_dirname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_filename(e, &_filename);
|
||||
r = path_split_prefix_filename(e, &_dirname, &_filename);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EINVAL;
|
||||
|
||||
/* We validate that the path is absolute above, hence dirname must be extractable. */
|
||||
dirname = _dirname;
|
||||
filename = _filename;
|
||||
} else {
|
||||
@ -498,7 +497,8 @@ int get_credential_host_secret(CredentialSecretFlags flags, struct iovec *ret) {
|
||||
assert(dirname);
|
||||
assert(filename);
|
||||
|
||||
mkdir_parents(dirname, 0755);
|
||||
(void) mkdir_parents(dirname, 0755);
|
||||
|
||||
dfd = open_mkdir(dirname, O_CLOEXEC, 0755);
|
||||
if (dfd < 0)
|
||||
return log_debug_errno(dfd, "Failed to create or open directory '%s': %m", dirname);
|
||||
|
||||
@ -109,13 +109,9 @@ int generator_add_symlink_full(
|
||||
*
|
||||
* If <instance> is specified, then <src> must be a template unit name, and we'll instantiate it. */
|
||||
|
||||
r = path_extract_directory(src, &dn);
|
||||
if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → just a file name was passed */
|
||||
return log_error_errno(r, "Failed to extract directory name from '%s': %m", src);
|
||||
|
||||
r = path_extract_filename(src, &fn);
|
||||
r = path_split_prefix_filename(src, &dn, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract file name from '%s': %m", src);
|
||||
return log_error_errno(r, "Failed to split '%s' into directory prefix and filename: %m", src);
|
||||
if (r == O_DIRECTORY)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Expected path to regular file name, but got '%s', refusing.", src);
|
||||
|
||||
|
||||
@ -12,9 +12,11 @@
|
||||
* See JOURNAL_SIZE_MAX in coredump.c */
|
||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
#define ENTRY_SIZE_MAX (1024*1024*770u)
|
||||
#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*32u)
|
||||
#define DATA_SIZE_MAX (1024*1024*768u)
|
||||
#else
|
||||
#define ENTRY_SIZE_MAX (1024*1024*13u)
|
||||
#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*8u)
|
||||
#define DATA_SIZE_MAX (1024*1024*11u)
|
||||
#endif
|
||||
#define LINE_CHUNK 8*1024u
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
||||
/* Note: none of these function change the file position of the provided fd, as they use pread() */
|
||||
|
||||
bool pe_header_is_64bit(const PeHeader *h) {
|
||||
assert(h);
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "discover-image.h"
|
||||
#include "log.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "snapshot-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "runtime-scope.h"
|
||||
#include "shared-forward.h"
|
||||
|
||||
/* create_ephemeral_snapshot - create a snapshot of the given directory.
|
||||
*
|
||||
|
||||
@ -291,17 +291,15 @@ int unit_file_resolve_symlink(
|
||||
dir, dir ? "/" : "", filename);
|
||||
|
||||
if (!dir) {
|
||||
r = path_extract_directory(filename, &_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
dir = _dir;
|
||||
|
||||
r = path_extract_filename(filename, &_filename);
|
||||
r = path_split_prefix_filename(filename, &_dir, &_filename);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EISDIR),
|
||||
"Unexpected path to a directory \"%s\", refusing.", filename);
|
||||
|
||||
/* We validate that the path is absolute above, hence dir must be extractable. */
|
||||
dir = ASSERT_PTR(_dir);
|
||||
filename = _filename;
|
||||
}
|
||||
|
||||
|
||||
@ -36,21 +36,37 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
||||
SD_VARLINK_DEFINE_FIELD_BY_TYPE(source, BootEntrySource, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("The string identifier of the entry"),
|
||||
SD_VARLINK_DEFINE_FIELD(id, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Path to the primary definition file for the entry"),
|
||||
SD_VARLINK_DEFINE_FIELD(path, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Directory path of the file system root the entry was found on"),
|
||||
SD_VARLINK_DEFINE_FIELD(root, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The entry's title string"),
|
||||
SD_VARLINK_DEFINE_FIELD(title, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The possibly mangled/augmented title to show for the entry"),
|
||||
SD_VARLINK_DEFINE_FIELD(showTitle, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("An explicitly configured sorting key for the enry"),
|
||||
SD_VARLINK_DEFINE_FIELD(sortKey, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The version of the entry"),
|
||||
SD_VARLINK_DEFINE_FIELD(version, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Machine ID of the OS installation belonging to the entry, if known"),
|
||||
SD_VARLINK_DEFINE_FIELD(machineId, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("EFI architecture name for this entry"),
|
||||
SD_VARLINK_DEFINE_FIELD(architecture, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Command line options to pass to the invoked kernel or EFI binary"),
|
||||
SD_VARLINK_DEFINE_FIELD(options, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Path to the Linux kernel to invoke, relative to the root directory of the file system containing the entry file"),
|
||||
SD_VARLINK_DEFINE_FIELD(linux, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Path to the EFI binary to invoke, relative to the root directory of the file system containing the entry file"),
|
||||
SD_VARLINK_DEFINE_FIELD(efi, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Path to an UKI EFI binary to invoke, relative to the root directory of the file system containing the entry file"),
|
||||
SD_VARLINK_DEFINE_FIELD(uki, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("An UKI profile index to invoke. If not specified defaults to the first profile."),
|
||||
SD_VARLINK_DEFINE_FIELD(profile, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Path to the initrd image to pass to the invoked kernel, relative to the root directory of the file system containing the entry file"),
|
||||
SD_VARLINK_DEFINE_FIELD(initrd, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
||||
SD_VARLINK_FIELD_COMMENT("Devicetree file to pass to the invoked kernel, relative to the root directory of the file system containing the entry file"),
|
||||
SD_VARLINK_DEFINE_FIELD(devicetree, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Devicetree overlay file to pass to the invoked kernel, relative to the root directory of the file system containing the entry file"),
|
||||
SD_VARLINK_DEFINE_FIELD(devicetreeOverlay, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
||||
SD_VARLINK_FIELD_COMMENT("Indicates whether the boot loader reported this entry on the current boot"),
|
||||
SD_VARLINK_DEFINE_FIELD(isReported, SD_VARLINK_BOOL, 0),
|
||||
@ -83,12 +99,53 @@ static SD_VARLINK_DEFINE_METHOD(
|
||||
SD_VARLINK_FIELD_COMMENT("The current state of the reboot-to-firmware-UI flag"),
|
||||
SD_VARLINK_DEFINE_OUTPUT(state, SD_VARLINK_BOOL, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_ENUM_TYPE(
|
||||
Operation,
|
||||
SD_VARLINK_FIELD_COMMENT("Install the boot loader afresh, creating everything it needs"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(new),
|
||||
SD_VARLINK_FIELD_COMMENT("Just update existing boot loader binaries"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(update));
|
||||
|
||||
static SD_VARLINK_DEFINE_ENUM_TYPE(
|
||||
BootEntryTokenType,
|
||||
SD_VARLINK_FIELD_COMMENT("Pick identifiers for type #1 boot entries based on /etc/machine-id"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(machine_id),
|
||||
SD_VARLINK_FIELD_COMMENT("Pick identifiers for type #1 boot entries based on the IMAGE_ID= field from /etc/os-release"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(os_image_id),
|
||||
SD_VARLINK_FIELD_COMMENT("Pick identifiers for type #1 boot entries based on the ID= field from /etc/os-release"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(os_id),
|
||||
SD_VARLINK_FIELD_COMMENT("Pick identifiers for type #1 boot entries based on a manually chosen string"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(literal),
|
||||
SD_VARLINK_FIELD_COMMENT("Choose automatically how to pick identifiers for type #1 boot entries"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(auto));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
Install,
|
||||
SD_VARLINK_FIELD_COMMENT("Operation, either 'new' or 'update'"),
|
||||
SD_VARLINK_DEFINE_INPUT_BY_TYPE(operation, Operation, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("If true, continue on various failures"),
|
||||
SD_VARLINK_DEFINE_INPUT(graceful, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Index into array of file descriptors passed along with this message, pointing to file descriptor to root file system to operate on"),
|
||||
SD_VARLINK_DEFINE_INPUT(rootFileDescriptor, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Root directory to operate relative to. If both this and rootFileDescriptor is specified, this is purely informational. If only this is specified, it is what will be used."),
|
||||
SD_VARLINK_DEFINE_INPUT(rootDirectory, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Selects how to identify boot entries"),
|
||||
SD_VARLINK_DEFINE_INPUT_BY_TYPE(bootEntryTokenType, BootEntryTokenType, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("If true the boot loader will be registered in an EFI boot entry via EFI variables, otherwise this is omitted"),
|
||||
SD_VARLINK_DEFINE_INPUT(touchVariables, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
|
||||
|
||||
static SD_VARLINK_DEFINE_ERROR(
|
||||
RebootToFirmwareNotSupported);
|
||||
|
||||
static SD_VARLINK_DEFINE_ERROR(
|
||||
NoSuchBootEntry);
|
||||
|
||||
static SD_VARLINK_DEFINE_ERROR(
|
||||
NoESPFound);
|
||||
|
||||
static SD_VARLINK_DEFINE_ERROR(
|
||||
BootEntryTokenUnavailable);
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_BootControl,
|
||||
"io.systemd.BootControl",
|
||||
@ -101,13 +158,23 @@ SD_VARLINK_DEFINE_INTERFACE(
|
||||
&vl_type_BootEntryAddon,
|
||||
SD_VARLINK_SYMBOL_COMMENT("A structure encapsulating a boot entry"),
|
||||
&vl_type_BootEntry,
|
||||
SD_VARLINK_SYMBOL_COMMENT("The operation to execute"),
|
||||
&vl_type_Operation,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Enumerates boot entries. Method call must be called with 'more' flag set. Each response returns one entry. If no entries are defined returns the NoSuchBootEntry error."),
|
||||
&vl_method_ListBootEntries,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Sets the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not."),
|
||||
&vl_method_SetRebootToFirmware,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Gets the current state of the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not."),
|
||||
&vl_method_GetRebootToFirmware,
|
||||
SD_VARLINK_SYMBOL_COMMENT("The boot entry token type to use."),
|
||||
&vl_type_BootEntryTokenType,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Install the boot loader on the ESP."),
|
||||
&vl_method_Install,
|
||||
SD_VARLINK_SYMBOL_COMMENT("SetRebootToFirmware() and GetRebootToFirmware() return this if the firmware does not actually support the reboot-to-firmware-UI concept."),
|
||||
&vl_error_RebootToFirmwareNotSupported,
|
||||
SD_VARLINK_SYMBOL_COMMENT("No boot entry defined."),
|
||||
&vl_error_NoSuchBootEntry);
|
||||
&vl_error_NoSuchBootEntry,
|
||||
SD_VARLINK_SYMBOL_COMMENT("No EFI System Partition (ESP) found."),
|
||||
&vl_error_NoESPFound,
|
||||
SD_VARLINK_SYMBOL_COMMENT("The select boot entry token could not be determined."),
|
||||
&vl_error_BootEntryTokenUnavailable);
|
||||
|
||||
@ -25,7 +25,7 @@ if conf.get('ENABLE_SSH_PROXY_CONFIG') == 1
|
||||
install : true,
|
||||
install_dir : sshconfdir.startswith('/usr/') ? sshconfdir : libexecdir / 'ssh_config.d')
|
||||
|
||||
if conf.get('LINK_SSH_PROXY_DROPIN') == 1
|
||||
if (not sshconfdir.startswith(sysconfdir) or install_sysconfdir) and conf.get('LINK_SSH_PROXY_DROPIN') == 1
|
||||
if meson.version().version_compare('>=1.3.0')
|
||||
install_symlink(
|
||||
'20-systemd-ssh-proxy.conf',
|
||||
|
||||
@ -26,7 +26,7 @@ int verb_preset_all(int argc, char *argv[], void *userdata) {
|
||||
CLEANUP_ARRAY(changes, n_changes, install_changes_free);
|
||||
|
||||
r = unit_file_preset_all(arg_runtime_scope, unit_file_flags_from_args(), arg_root, arg_preset_mode, &changes, &n_changes);
|
||||
/* We do not treat propagate failure of individual units here. */
|
||||
/* We do not propagate failure for individual units here. */
|
||||
(void) install_changes_dump(r, "preset all", changes, n_changes, arg_quiet);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1027,7 +1027,7 @@ TEST(last_path_component) {
|
||||
}
|
||||
|
||||
static void test_path_extract_filename_one(const char *input, const char *output, int ret) {
|
||||
_cleanup_free_ char *k = NULL;
|
||||
_cleanup_free_ char *k = NULL, *k2 = NULL;
|
||||
int r;
|
||||
|
||||
r = path_extract_filename(input, &k);
|
||||
@ -1037,6 +1037,13 @@ static void test_path_extract_filename_one(const char *input, const char *output
|
||||
strnull(output), ret < 0 ? STRERROR(ret) : "-");
|
||||
ASSERT_STREQ(k, output);
|
||||
assert_se(r == ret);
|
||||
|
||||
/* Extra safety check: make sure that path_split_prefix_filename() behaves the same */
|
||||
r = path_split_prefix_filename(input, NULL, &k2);
|
||||
if (r >= 0) {
|
||||
ASSERT_STREQ(k2, k);
|
||||
assert_se(r == ret);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(path_extract_filename) {
|
||||
@ -1071,7 +1078,7 @@ TEST(path_extract_filename) {
|
||||
}
|
||||
|
||||
static void test_path_extract_directory_one(const char *input, const char *output, int ret) {
|
||||
_cleanup_free_ char *k = NULL;
|
||||
_cleanup_free_ char *k = NULL, *k2 = NULL;
|
||||
int r;
|
||||
|
||||
r = path_extract_directory(input, &k);
|
||||
@ -1082,10 +1089,18 @@ static void test_path_extract_directory_one(const char *input, const char *outpu
|
||||
ASSERT_STREQ(k, output);
|
||||
assert_se(r == ret);
|
||||
|
||||
/* Extra safety check: make sure that path_split_prefix_filename() behaves the same.
|
||||
* We can’t check the return value from it though as that differs based on the filename component.
|
||||
* We can only assert that if path_extract_directory() fails, then
|
||||
* path_split_prefix_filename() must also fail. */
|
||||
r = path_split_prefix_filename(input, &k2, NULL);
|
||||
ASSERT_STREQ(k2, k);
|
||||
assert_se(!(ret < 0) || r < 0);
|
||||
|
||||
/* Extra safety check: let's make sure that if we split out the filename too (and it works) the
|
||||
* joined parts are identical to the original again */
|
||||
if (r >= 0) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
_cleanup_free_ char *f = NULL, *k3 = NULL, *f2 = NULL;
|
||||
|
||||
r = path_extract_filename(input, &f);
|
||||
if (r >= 0) {
|
||||
@ -1094,6 +1109,13 @@ static void test_path_extract_directory_one(const char *input, const char *outpu
|
||||
assert_se(j = path_join(k, f));
|
||||
assert_se(path_equal(input, j));
|
||||
}
|
||||
|
||||
/* And the same, but for path_split_prefix_filename() */
|
||||
r = path_split_prefix_filename(input, &k3, &f2);
|
||||
if (r >= 0) {
|
||||
ASSERT_STREQ(k3, k);
|
||||
ASSERT_STREQ(f2, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ if conf.get('ENABLE_SSH_USERDB_CONFIG') == 1
|
||||
install : true,
|
||||
install_dir : sshdconfdir.startswith('/usr/') ? sshdconfdir : libexecdir / 'sshd_config.d')
|
||||
|
||||
if conf.get('LINK_SSHD_USERDB_DROPIN') == 1
|
||||
if (not sshdconfdir.startswith(sysconfdir) or install_sysconfdir) and conf.get('LINK_SSHD_USERDB_DROPIN') == 1
|
||||
if meson.version().version_compare('>=1.3.0')
|
||||
install_symlink(
|
||||
'20-systemd-userdb.conf',
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#include "build.h"
|
||||
#include "bus-util.h"
|
||||
#include "chase.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -21,10 +22,14 @@
|
||||
#include "pager.h"
|
||||
#include "parse-argument.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "pidfd-util.h"
|
||||
#include "polkit-agent.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
@ -49,6 +54,8 @@ static usec_t arg_timeout = 0;
|
||||
static bool arg_exec = false;
|
||||
static PushFds arg_push_fds = {};
|
||||
static bool arg_ask_password = true;
|
||||
static bool arg_legend = true;
|
||||
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||
|
||||
static void push_fds_done(PushFds *p) {
|
||||
assert(p);
|
||||
@ -85,6 +92,7 @@ static int help(void) {
|
||||
" Invoke method\n"
|
||||
" --exec call ADDRESS METHOD PARAMS -- CMDLINE…\n"
|
||||
" Invoke method and pass response and fds to command\n"
|
||||
" list-registry Show list of services in the service registry\n"
|
||||
" validate-idl [FILE] Validate interface description\n"
|
||||
" help Show this help\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
@ -92,6 +100,8 @@ static int help(void) {
|
||||
" --version Show package version\n"
|
||||
" --no-ask-password Do not prompt for password\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --system Enumerate system registry\n"
|
||||
" --user Enumerate user registry\n"
|
||||
" --more Request multiple responses\n"
|
||||
" --collect Collect multiple responses in a JSON array\n"
|
||||
" --oneway Do not request response\n"
|
||||
@ -131,6 +141,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_EXEC,
|
||||
ARG_PUSH_FD,
|
||||
ARG_NO_ASK_PASSWORD,
|
||||
ARG_USER,
|
||||
ARG_SYSTEM,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -147,6 +159,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "exec", no_argument, NULL, ARG_EXEC },
|
||||
{ "push-fd", required_argument, NULL, ARG_PUSH_FD },
|
||||
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
||||
{ "user", no_argument, NULL, ARG_USER },
|
||||
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -263,6 +277,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_ask_password = false;
|
||||
break;
|
||||
|
||||
case ARG_USER:
|
||||
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
||||
break;
|
||||
|
||||
case ARG_SYSTEM:
|
||||
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -973,6 +995,105 @@ static int verb_validate_idl(int argc, char *argv[], void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_list_registry(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
assert(argc <= 1);
|
||||
|
||||
_cleanup_free_ char *reg_path = NULL;
|
||||
r = runtime_directory_generic(arg_runtime_scope, "varlink/registry", ®_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine registry path: %m");
|
||||
|
||||
_cleanup_(table_unrefp) Table *table = table_new("interface", "entrypoint");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
(void) table_set_sort(table, (size_t) 0);
|
||||
|
||||
_cleanup_close_ int regfd = open(reg_path, O_DIRECTORY|O_CLOEXEC);
|
||||
if (regfd < 0) {
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to open '%s': %m", reg_path);
|
||||
} else {
|
||||
_cleanup_free_ DirectoryEntries *des = NULL;
|
||||
r = readdir_all(regfd, RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate '%s': %m", reg_path);
|
||||
|
||||
FOREACH_ARRAY(i, des->entries, des->n_entries) {
|
||||
struct dirent *de = *i;
|
||||
|
||||
if (!varlink_idl_interface_name_is_valid(de->d_name)) {
|
||||
log_debug("Found file '%s' whose names does not qualify as valid Varlink interface name, skipping.", de->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *j = path_join(reg_path, de->d_name);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
switch (de->d_type) {
|
||||
case DT_LNK: {
|
||||
_cleanup_free_ char *resolved = NULL;
|
||||
|
||||
r = chase(j, /* root= */ NULL, CHASE_MUST_BE_SOCKET, &resolved, /* ret_fd= */ NULL);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to resolve '%s', skipping: %m", j);
|
||||
continue;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *address = strjoin("unix:", resolved);
|
||||
if (!address)
|
||||
return log_oom();
|
||||
|
||||
r = table_add_many(
|
||||
table,
|
||||
TABLE_STRING, de->d_name,
|
||||
TABLE_STRING, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DT_SOCK: {
|
||||
_cleanup_free_ char *address = strjoin("unix:", j);
|
||||
if (!address)
|
||||
return log_oom();
|
||||
|
||||
r = table_add_many(
|
||||
table,
|
||||
TABLE_STRING, de->d_name,
|
||||
TABLE_STRING, address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log_debug("Ignoring inode '%s' of unexpected type: %m", de->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!table_isempty(table) || sd_json_format_enabled(arg_json_format_flags)) {
|
||||
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */ true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to output table: %m");
|
||||
}
|
||||
|
||||
if (arg_legend && !sd_json_format_enabled(arg_json_format_flags)) {
|
||||
if (table_isempty(table))
|
||||
printf("No services registered.\n");
|
||||
else
|
||||
printf("\n%zu registered services listed.\n", table_get_rows(table) - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int varlinkctl_main(int argc, char *argv[]) {
|
||||
static const Verb verbs[] = {
|
||||
{ "info", 2, 2, 0, verb_info },
|
||||
@ -980,6 +1101,7 @@ static int varlinkctl_main(int argc, char *argv[]) {
|
||||
{ "introspect", 2, VERB_ANY, 0, verb_introspect },
|
||||
{ "list-methods", 2, VERB_ANY, 0, verb_introspect },
|
||||
{ "call", 3, VERB_ANY, 0, verb_call },
|
||||
{ "list-registry", VERB_ANY, 1, 0, verb_list_registry },
|
||||
{ "validate-idl", 1, 2, 0, verb_validate_idl },
|
||||
{ "help", VERB_ANY, VERB_ANY, 0, verb_help },
|
||||
{}
|
||||
|
||||
@ -42,7 +42,7 @@ if git.found() and fs.is_dir(meson.project_source_root() / '.git')
|
||||
'ls-files', ':/@0@/*/*'.format(fuzz_testsdir),
|
||||
check: true)
|
||||
else
|
||||
out = run_command(sh, '-c', 'cd "@0@"; echo @1@/*/*'.format(meson.project_source_root(), fuzz_testsdir), check: true)
|
||||
out = run_command(sh, '-c', 'cd "@0@"; printf "%s " @1@/*/*'.format(meson.project_source_root(), fuzz_testsdir), check: true)
|
||||
endif
|
||||
|
||||
# Add crafted fuzz inputs we have in the repo
|
||||
|
||||
@ -37,6 +37,10 @@ varlinkctl introspect -j /run/systemd/journal/io.systemd.journal | jq --seq .
|
||||
varlinkctl introspect /run/systemd/journal/io.systemd.journal io.systemd.Journal
|
||||
varlinkctl introspect -j /run/systemd/journal/io.systemd.journal io.systemd.Journal | jq .
|
||||
|
||||
varlinkctl list-registry
|
||||
varlinkctl list-registry -j | jq .
|
||||
varlinkctl list-registry | grep io.systemd.Manager
|
||||
|
||||
if command -v userdbctl >/dev/null; then
|
||||
systemctl start systemd-userdbd
|
||||
varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{ "userName" : "testuser", "service" : "io.systemd.Multiplexer" }'
|
||||
|
||||
@ -27,9 +27,11 @@ restore_esp() {
|
||||
fi
|
||||
|
||||
if [ -d /tmp/esp.bak/EFI/ ]; then
|
||||
mkdir -p "$(bootctl --print-esp-path)/EFI/"
|
||||
cp -r /tmp/esp.bak/EFI/* "$(bootctl --print-esp-path)/EFI/"
|
||||
fi
|
||||
if [ -d /tmp/esp.bak/loader/ ]; then
|
||||
mkdir -p "$(bootctl --print-esp-path)/loader/"
|
||||
cp -r /tmp/esp.bak/loader/* "$(bootctl --print-esp-path)/loader/"
|
||||
fi
|
||||
rm -rf /tmp/esp.bak
|
||||
@ -40,13 +42,19 @@ backup_esp() {
|
||||
return
|
||||
fi
|
||||
|
||||
# make a backup of the two key dirs in the ESP, and delete them
|
||||
|
||||
if [[ -d "$(bootctl --print-esp-path)/EFI" ]]; then
|
||||
mkdir -p /tmp/esp.bak
|
||||
cp -r "$(bootctl --print-esp-path)/EFI/" /tmp/esp.bak/
|
||||
rm -rf "$(bootctl --print-esp-path)/EFI"
|
||||
mkdir "$(bootctl --print-esp-path)/EFI"
|
||||
fi
|
||||
if [[ -d "$(bootctl --print-esp-path)/loader" ]]; then
|
||||
mkdir -p /tmp/esp.bak
|
||||
cp -r "$(bootctl --print-esp-path)/loader/" /tmp/esp.bak/
|
||||
rm -rf "$(bootctl --print-esp-path)/loader"
|
||||
mkdir "$(bootctl --print-esp-path)/loader"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -364,4 +372,22 @@ testcase_00_secureboot() {
|
||||
grep -q addonfoobar /proc/cmdline
|
||||
}
|
||||
|
||||
remove_root_dir() {
|
||||
rm -rf "$ROOTDIR"
|
||||
}
|
||||
|
||||
testcase_install_varlink() {
|
||||
|
||||
varlinkctl introspect "$(type -p bootctl)"
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
backup_esp
|
||||
trap restore_esp RETURN ERR
|
||||
fi
|
||||
|
||||
(! bootctl is-installed )
|
||||
SYSTEMD_LOG_TARGET=console varlinkctl call "$(type -p bootctl)" io.systemd.BootControl.Install "{\"operation\":\"new\",\"touchVariables\":false}"
|
||||
bootctl is-installed
|
||||
}
|
||||
|
||||
run_testcases
|
||||
|
||||
18
tmpfiles.d/20-systemd-varlink.conf
Normal file
18
tmpfiles.d/20-systemd-varlink.conf
Normal file
@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# See tmpfiles.d(5) for details.
|
||||
|
||||
# Varlink AF_UNIX entrypoint socket inodes of relevant system services may be
|
||||
# linked into this directory, to make them "well-known". Typically, tools such
|
||||
# as the Varlink HTTP bridge expose services linked in here as public
|
||||
# interfaces. The symlink should be named after the Varlink interface to
|
||||
# expose. Interfaces that may be implemented by multiple services (such as
|
||||
# the generic "io.systemd.service") should not be symlinked here.
|
||||
d /run/varlink/registry/ 0755 root root
|
||||
|
||||
# Socket activated services should use Symlinks= in the .socket unit file to
|
||||
# create these symlinks. If that's not applicable, consider creating the
|
||||
# symlinks via a tmpfiles.d/ snippet, like we do here, so that registration can
|
||||
# be influenced by the administrator.
|
||||
L /run/varlink/registry/io.systemd.Unit - - - - ../../systemd/io.systemd.Manager
|
||||
L /run/varlink/registry/io.systemd.Manager - - - - ../../systemd/io.systemd.Manager
|
||||
L /run/varlink/registry/io.systemd.Journal - - - - ../../systemd/journal/io.systemd.journal
|
||||
@ -13,6 +13,7 @@ files = [['README' ],
|
||||
['systemd-nspawn.conf', 'ENABLE_MACHINED' ],
|
||||
['systemd-pstore.conf', 'ENABLE_PSTORE' ],
|
||||
['systemd-resolve.conf', 'ENABLE_RESOLVE' ],
|
||||
['20-systemd-varlink.conf' ],
|
||||
['systemd-tmp.conf' ],
|
||||
['tmp.conf' ],
|
||||
['x11.conf' ],
|
||||
@ -59,3 +60,5 @@ endforeach
|
||||
if install_sysconfdir
|
||||
install_emptydir(sysconfdir / 'tmpfiles.d')
|
||||
endif
|
||||
|
||||
subdir('user')
|
||||
|
||||
7
tmpfiles.d/user/20-systemd-varlink.conf
Normal file
7
tmpfiles.d/user/20-systemd-varlink.conf
Normal file
@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# See tmpfiles.d(5) for details.
|
||||
|
||||
d %t/varlink/registry/ 0755
|
||||
|
||||
L %t/varlink/registry/io.systemd.Unit - - - - ../../systemd/io.systemd.Manager
|
||||
L %t/varlink/registry/io.systemd.Manager - - - - ../../systemd/io.systemd.Manager
|
||||
11
tmpfiles.d/user/meson.build
Normal file
11
tmpfiles.d/user/meson.build
Normal file
@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
files = [ '20-systemd-varlink.conf' ]
|
||||
|
||||
foreach f : files
|
||||
install_data(f, install_dir : usertmpfilesdir)
|
||||
endforeach
|
||||
|
||||
if install_sysconfdir
|
||||
install_emptydir(sysconfdir / 'user-tmpfiles.d')
|
||||
endif
|
||||
@ -572,3 +572,4 @@ loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="rebo
|
||||
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="reboot-on-error"]/listitem/para/variablelist/varlistentry[term="auto"]
|
||||
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="reboot"]
|
||||
loader.conf.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="secure-boot-enroll-action"]/listitem/variablelist/varlistentry[term="shutdown"]
|
||||
varlinkctl.xml ./refsect1[title="Options"]/variablelist/varlistentry[term="--system"]
|
||||
|
||||
@ -15,6 +15,7 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.AskPassword
|
||||
Symlinks=/run/varlink/registry/io.systemd.AskPassword
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Accept=yes
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Boot Entries Service Socket
|
||||
Description=Boot Loader Control Service Socket
|
||||
Documentation=man:bootctl(1)
|
||||
DefaultDependencies=no
|
||||
After=local-fs.target
|
||||
@ -16,6 +16,7 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.BootControl
|
||||
Symlinks=/run/varlink/registry/io.systemd.BootControl
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=Boot Entries Service
|
||||
Description=Boot Loader Control Service
|
||||
Documentation=man:bootctl(1)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
|
||||
@ -15,6 +15,7 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.Credentials
|
||||
Symlinks=/run/varlink/registry/io.systemd.Credentials
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Accept=yes
|
||||
|
||||
@ -15,6 +15,7 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.FactoryReset
|
||||
Symlinks=/run/varlink/registry/io.systemd.FactoryReset
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Accept=yes
|
||||
|
||||
@ -15,5 +15,6 @@ Documentation=man:machine-info(5)
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.Hostname
|
||||
Symlinks=/run/varlink/registry/io.systemd.Hostname
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
|
||||
@ -20,5 +20,6 @@ Before=shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.Import
|
||||
Symlinks=/run/varlink/registry/io.systemd.Import
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
|
||||
@ -13,6 +13,7 @@ Documentation=man:systemd-logind.service(8)
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.Login
|
||||
Symlinks=/run/varlink/registry/io.systemd.Login
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Service=systemd-logind.service
|
||||
|
||||
@ -13,6 +13,6 @@ Documentation=man:systemd-machined.service(8)
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/machine/io.systemd.Machine
|
||||
ListenStream=/run/systemd/machine/io.systemd.MachineImage
|
||||
Symlinks=/run/systemd/machine/io.systemd.MachineImage /run/varlink/registry/io.systemd.Machine /run/varlink/registry/io.systemd.MachineImage
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
|
||||
@ -16,6 +16,8 @@ Before=sockets.target shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.MountFileSystem
|
||||
Symlinks=/run/varlink/registry/io.systemd.MountFileSystem
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
|
||||
[Install]
|
||||
|
||||
@ -17,6 +17,7 @@ Before=shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.MuteConsole
|
||||
Symlinks=/run/varlink/registry/io.systemd.MuteConsole
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
|
||||
@ -17,6 +17,7 @@ Conflicts=shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/netif/io.systemd.Network
|
||||
Symlinks=/run/varlink/registry/io.systemd.Network
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Service=systemd-networkd.service
|
||||
|
||||
@ -16,7 +16,8 @@ Before=sockets.target shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.NamespaceResource
|
||||
Symlinks=/run/systemd/userdb/io.systemd.NamespaceResource
|
||||
Symlinks=/run/systemd/userdb/io.systemd.NamespaceResource /run/varlink/registry/io.systemd.NamespaceResource
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
|
||||
[Install]
|
||||
|
||||
@ -17,6 +17,7 @@ ConditionSecurity=measured-uki
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.PCRExtend
|
||||
Symlinks=/run/varlink/registry/io.systemd.PCRExtend
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
|
||||
@ -17,6 +17,7 @@ ConditionSecurity=measured-uki
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.PCRLock
|
||||
Symlinks=/run/varlink/registry/io.systemd.PCRLock
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
|
||||
@ -17,6 +17,7 @@ Before=shutdown.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.Repart
|
||||
Symlinks=/run/varlink/registry/io.systemd.Repart
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
|
||||
@ -17,6 +17,7 @@ Conflicts=shutdown.target
|
||||
[Socket]
|
||||
Service=systemd-resolved.service
|
||||
ListenStream=/run/systemd/resolve/io.systemd.Resolve.Monitor
|
||||
Symlinks=/run/varlink/registry/io.systemd.Resolve.Monitor
|
||||
FileDescriptorName=varlink-monitor
|
||||
SocketMode=0666
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ Conflicts=shutdown.target
|
||||
[Socket]
|
||||
Service=systemd-resolved.service
|
||||
ListenStream=/run/systemd/resolve/io.systemd.Resolve
|
||||
Symlinks=/run/varlink/registry/io.systemd.Resolve
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ ConditionCapability=CAP_SYS_ADMIN
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/io.systemd.sysext
|
||||
Symlinks=/run/varlink/registry/io.systemd.sysext
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
Accept=yes
|
||||
|
||||
@ -17,6 +17,7 @@ ConditionPathIsReadWrite=/sys
|
||||
[Socket]
|
||||
Service=systemd-udevd.service
|
||||
ListenStream=/run/udev/io.systemd.Udev
|
||||
Symlinks=/run/varlink/registry/io.systemd.Udev
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
RemoveOnStop=yes
|
||||
|
||||
@ -15,7 +15,8 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/systemd/userdb/io.systemd.Multiplexer
|
||||
Symlinks=/run/systemd/userdb/io.systemd.NameServiceSwitch /run/systemd/userdb/io.systemd.DropIn
|
||||
Symlinks=/run/systemd/userdb/io.systemd.NameServiceSwitch /run/systemd/userdb/io.systemd.DropIn /run/varlink/registry/io.systemd.UserDatabase
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0666
|
||||
RemoveOnStop=yes
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/systemd/io.systemd.AskPassword
|
||||
Symlinks=%t/varlink/registry/io.systemd.AskPassword
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
|
||||
@ -14,5 +14,6 @@ Documentation=man:org.freedesktop.import1(5)
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/systemd/io.systemd.Import
|
||||
Symlinks=%t/varlink/registry/io.systemd.Import
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
|
||||
@ -13,6 +13,6 @@ Documentation=man:systemd-machined.service(8)
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/systemd/machine/io.systemd.Machine
|
||||
ListenStream=%t/systemd/machine/io.systemd.MachineImage
|
||||
Symlinks=%t/systemd/machine/io.systemd.MachineImage %t/varlink/registry/io.systemd.Machine %t/varlink/registry/io.systemd.MachineImage
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user