summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dir-locals.el10
-rw-r--r--.lgtm.yml10
-rw-r--r--NEWS27
-rw-r--r--README4
-rw-r--r--TODO20
-rw-r--r--doc/BOOT_LOADER_SPECIFICATION.md40
-rw-r--r--doc/TRANSIENT-SETTINGS.md1
-rw-r--r--hwdb/60-sensor.hwdb15
-rw-r--r--man/.dir-locals.el10
-rw-r--r--man/coredumpctl.xml3
-rw-r--r--man/nss-myhostname.xml2
-rw-r--r--man/nss-mymachines.xml2
-rw-r--r--man/nss-resolve.xml2
-rw-r--r--man/pam_systemd.xml109
-rw-r--r--man/rules/meson.build7
-rw-r--r--man/systemctl.xml16
-rw-r--r--man/systemd-run.xml10
-rw-r--r--man/systemd-system.conf.xml10
-rw-r--r--man/systemd.kill.xml27
-rw-r--r--man/systemd.service.xml158
-rw-r--r--man/systemd.special.xml1880
-rw-r--r--man/user@.service.xml190
-rw-r--r--meson.build172
-rw-r--r--meson_options.txt47
-rw-r--r--shell-completion/bash/systemd-run4
-rw-r--r--shell-completion/zsh/_systemd-run4
-rw-r--r--src/analyze/analyze.c130
-rw-r--r--src/basic/btrfs-util.c24
-rw-r--r--src/basic/cgroup-util.c7
-rw-r--r--src/basic/fileio.c38
-rw-r--r--src/basic/fs-util.c38
-rw-r--r--src/basic/fs-util.h2
-rw-r--r--src/basic/mount-util.c8
-rw-r--r--src/basic/parse-util.c7
-rw-r--r--src/basic/util.c30
-rw-r--r--src/basic/util.h1
-rw-r--r--src/boot/efi/measure.c2
-rw-r--r--src/boot/efi/measure.h2
-rw-r--r--src/boot/efi/meson.build4
-rw-r--r--src/boot/efi/stub.c1
-rw-r--r--src/core/bpf-firewall.c1
-rw-r--r--src/core/dbus-kill.c5
-rw-r--r--src/core/dbus-manager.c8
-rw-r--r--src/core/emergency-action.c3
-rw-r--r--src/core/emergency-action.h4
-rw-r--r--src/core/execute.c103
-rw-r--r--src/core/execute.h13
-rw-r--r--src/core/job.c1
-rw-r--r--src/core/kill.c3
-rw-r--r--src/core/kill.h1
-rw-r--r--src/core/load-fragment-gperf.gperf.m43
-rw-r--r--src/core/load-fragment.c12
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/main.c93
-rw-r--r--src/core/manager.c47
-rw-r--r--src/core/manager.h8
-rw-r--r--src/core/mount.c9
-rw-r--r--src/core/service.c192
-rw-r--r--src/core/service.h4
-rw-r--r--src/core/show-status.c26
-rw-r--r--src/core/show-status.h13
-rw-r--r--src/core/socket.c9
-rw-r--r--src/core/swap.c1
-rw-r--r--src/core/unit.c2
-rw-r--r--src/coredump/coredumpctl.c3
-rw-r--r--src/escape/escape.c3
-rw-r--r--src/import/export-raw.c7
-rw-r--r--src/journal/fsprg.h1
-rw-r--r--src/journal/journal-def.h1
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c4
-rw-r--r--src/libsystemd/sd-device/device-internal.h2
-rw-r--r--src/libsystemd/sd-hwdb/sd-hwdb.c1
-rw-r--r--src/libsystemd/sd-login/sd-login.c27
-rw-r--r--src/login/70-uaccess.rules.m4 (renamed from src/login/70-uaccess.rules)4
-rw-r--r--src/login/logind-user.c6
-rw-r--r--src/login/meson.build13
-rw-r--r--src/login/org.freedesktop.login1.policy2
-rw-r--r--src/login/pam_systemd.c255
-rw-r--r--src/machine/machine-dbus.c8
-rw-r--r--src/network/netdev/vrf.c3
-rw-r--r--src/network/netdev/vrf.h4
-rw-r--r--src/network/networkd-dhcp6.c12
-rw-r--r--src/network/networkd-manager.c4
-rw-r--r--src/network/test-network-tables.c1
-rw-r--r--src/nspawn/nspawn-cgroup.c421
-rw-r--r--src/nspawn/nspawn-cgroup.h3
-rw-r--r--src/nspawn/nspawn-mount.c457
-rw-r--r--src/nspawn/nspawn-mount.h7
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/nss-myhostname/nss-myhostname.c16
-rw-r--r--src/nss-mymachines/nss-mymachines.c88
-rw-r--r--src/nss-resolve/nss-resolve.c87
-rw-r--r--src/nss-systemd/nss-systemd.c74
-rw-r--r--src/portable/portabled-image.c1
-rw-r--r--src/resolve/resolved-dns-dnssec.c1
-rw-r--r--src/resolve/resolved-dns-server.c2
-rw-r--r--src/resolve/resolved-dns-server.h3
-rw-r--r--src/resolve/test-resolve-tables.c7
-rw-r--r--src/shared/bus-unit-util.c24
-rw-r--r--src/shared/initreq.h2
-rw-r--r--src/shared/meson.build5
-rw-r--r--src/shared/specifier.c1
-rw-r--r--src/systemctl/systemctl.c4
-rw-r--r--src/test/meson.build2
-rw-r--r--src/test/test-nss.c6
-rw-r--r--src/test/test-process-util.c10
-rw-r--r--src/test/test-tables.c6
-rw-r--r--src/time-wait-sync/time-wait-sync.c1
-rw-r--r--src/udev/ata_id/ata_id.c1
-rw-r--r--src/udev/cdrom_id/cdrom_id.c2
-rw-r--r--src/udev/collect/collect.c1
-rw-r--r--src/udev/scsi_id/scsi_id.c1
-rw-r--r--src/udev/scsi_id/scsi_id.h1
-rw-r--r--src/udev/scsi_id/scsi_serial.c1
-rw-r--r--src/udev/udev-builtin-blkid.c1
-rw-r--r--src/udev/udev-builtin-input_id.c1
-rw-r--r--src/udev/udev-builtin-kmod.c1
-rw-r--r--src/udev/udev-builtin-path_id.c2
-rw-r--r--src/udev/udev-builtin-uaccess.c2
-rw-r--r--src/udev/udev-builtin-usb_id.c2
-rw-r--r--src/udev/udev-ctrl.c1
-rw-r--r--src/udev/udev-event.c3
-rw-r--r--src/udev/udev-node.c3
-rw-r--r--src/udev/udev-rules.c3
-rw-r--r--src/udev/udev-watch.c1
-rw-r--r--src/udev/udev.h1
-rw-r--r--src/udev/udevadm-control.c1
-rw-r--r--src/udev/udevadm-info.c3
-rw-r--r--src/udev/udevadm-monitor.c3
-rw-r--r--src/udev/udevadm-settle.c1
-rw-r--r--src/udev/udevadm-test-builtin.c3
-rw-r--r--src/udev/udevadm-test.c1
-rw-r--r--src/udev/udevadm-trigger.c3
-rw-r--r--src/udev/udevadm-util.c3
-rw-r--r--src/udev/udevadm-util.h3
-rw-r--r--src/udev/udevadm.c3
-rw-r--r--src/udev/udevd.c1
-rw-r--r--test/TEST-23-TYPE-EXEC/Makefile4
-rwxr-xr-xtest/TEST-23-TYPE-EXEC/test.sh42
-rwxr-xr-xtest/TEST-23-TYPE-EXEC/testsuite.sh28
-rwxr-xr-xtools/check-includes.pl2
-rwxr-xr-xtools/meson-build.sh2
-rw-r--r--tools/meson-link-test.c1
-rw-r--r--units/user-.slice.d/10-defaults.conf1
-rw-r--r--units/user-runtime-dir@.service.in1
-rw-r--r--units/user@.service.in4
146 files changed, 3012 insertions, 2353 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index 5ef7e11634..e3d01b28a9 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -9,10 +9,7 @@
; NOTE: If you update this file make sure to update .vimrc and .editorconfig,
; too.
-((nil . ((indent-tabs-mode . nil)
- (tab-width . 8)
- (fill-column . 79)))
- (c-mode . ((fill-column . 119)
+((c-mode . ((fill-column . 119)
(c-basic-offset . 8)
(eval . (c-set-offset 'substatement-open 0))
(eval . (c-set-offset 'statement-case-open 0))
@@ -24,4 +21,7 @@
(meson-mode . ((meson-indent-basic . 8)))
(sh-mode . ((sh-basic-offset . 8)
(sh-indentation . 8)))
- (awk-mode . ((c-basic-offset . 8))))
+ (awk-mode . ((c-basic-offset . 8)))
+ (nil . ((indent-tabs-mode . nil)
+ (tab-width . 8)
+ (fill-column . 79))) )
diff --git a/.lgtm.yml b/.lgtm.yml
new file mode 100644
index 0000000000..37f9c4335c
--- /dev/null
+++ b/.lgtm.yml
@@ -0,0 +1,10 @@
+extraction:
+ cpp:
+ prepare:
+ packages:
+ - python3-pip
+ - python3-setuptools
+ - python3-wheel
+ after_prepare:
+ - pip3 install meson
+ - export PATH="$HOME/.local/bin/:$PATH"
diff --git a/NEWS b/NEWS
index da6142b9a3..242f55af29 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,32 @@
systemd System and Service Manager
+CHANGES WITH 240 in spe:
+
+ * A new service type has been added: Type=exec. It's very similar to
+ Type=simple and ensures the service manager will wait for both fork()
+ and execve() of the main service binary to complete before proceeding
+ with follow-up units. This is primarily useful so that the manager
+ propagates any errors in the preparation phase of service execution
+ back to the job that requested the unit to be started. For example,
+ consider a service that has ExecStart= set to a file system binary
+ that doesn't exist. With Type=simple starting the unit would
+ typically succeed instantly, as only fork() has to complete
+ successfully and execve() is not waited for, and hence its failure is
+ seen "too late". With the new Type=exec service type starting the
+ unit will fail, as the execve() will be waited for and will fail,
+ which is then propagated back to the start job.
+
+ NOTE: with the next release 241 of systemd we intend to change the
+ systemd-run tool to default to Type=exec for transient services
+ started by it. This should be mostly safe, but in specific corner
+ cases might result in problems, as the systemd-run tool will then
+ block on NSS calls (such as user name lookups due to User=) done
+ between the fork() and execve(), which under specific circumstances
+ might cause problems. It is recommended to specify "-p Type=simple"
+ explicitly in the few cases where this applies. For regular,
+ non-transient services (i.e. those defined with unit files on disk)
+ we will continue to default to Type=simple.
+
CHANGES WITH 239:
* NETWORK INTERFACE DEVICE NAMING CHANGES: systemd-udevd's "net_id"
diff --git a/README b/README
index 82f47a59ab..c0b264abf4 100644
--- a/README
+++ b/README
@@ -162,14 +162,14 @@ REQUIREMENTS:
docbook-xsl (optional, required for documentation)
xsltproc (optional, required for documentation)
python-lxml (optional, required to build the indices)
- python >= 3.4, meson >= 0.44, ninja
+ python >= 3.5, meson >= 0.46, ninja
gcc, awk, sed, grep, m4, and similar tools
During runtime, you need the following additional
dependencies:
util-linux >= v2.27.1 required
- dbus >= 1.4.0 (strictly speaking optional, but recommended)
+ dbus >= 1.9.14 (strictly speaking optional, but recommended)
NOTE: If using dbus < 1.9.18, you should override the default
policy directory (--with-dbuspolicydir=/etc/dbus-1/system.d).
dracut (optional)
diff --git a/TODO b/TODO
index 40622aa048..9bb01fd574 100644
--- a/TODO
+++ b/TODO
@@ -21,6 +21,22 @@ Janitorial Clean-ups:
Features:
+* logind: maybe watch utmp asynchronously using inotify, and populate our own
+ tracked session metadata from the fields available therein. Why bother? Right
+ now, all "ssh" sessions will be tracked without their TTY by logind (which is
+ not just unfriendly to users as this means "loginctl session-status" shows
+ less information than "who" in many cases, but also breaks the IdleAction
+ logic, as we never can detect such sessions as idle, as we have no TTY to
+ watch). ssh sets the PAM_TTY field on its PAM sessions to "ssh" rather than
+ the actual pty, because the PAM session is opened early on for new
+ connections, but the PTY only registered much later (if at all). ssh writes
+ the utmp record only after a TTY is actually registered, hence we could use
+ this data then, and use it if it is available. Using utmp for this is ugly of
+ course, and watching things asynchronously even more so, but it should be
+ good enough for the idle detection logic at least.
+
+* maybe extend .path units to expose fanotify() per-mount change events
+
* Add a "systemctl list-units --by-slice" mode or so, which rearranges the
output of "systemctl list-units" slightly by showing the tree structure of
the slices, and the units attached to them.
@@ -55,10 +71,6 @@ Features:
that our log messages could contain clickable links for example for unit
files and suchlike we operate on.
-* introduce a new SystemCallFilters= group called "@system-service" with a
- sensible default set for system services, then make use of them in portable
- profiles
-
* add support for "portablectl attach http://foobar.com/waaa.raw (i.e. importd integration)
* add attach --enable and attach --now (for attach+enable+start)
diff --git a/doc/BOOT_LOADER_SPECIFICATION.md b/doc/BOOT_LOADER_SPECIFICATION.md
index 4d79cb1279..bea380de8c 100644
--- a/doc/BOOT_LOADER_SPECIFICATION.md
+++ b/doc/BOOT_LOADER_SPECIFICATION.md
@@ -15,9 +15,9 @@ Of course, without this specification things already work mostly fine. But here'
* To make the boot more robust, as no explicit rewriting of configuration files is required any more
* To improve dual-boot scenarios. Currently, multiple Linux installations tend to fight over which boot loader becomes the primary one in possession of the MBR, and only that one installation can then update the boot loader configuration of it freely. Other Linux installs have to be manually configured to never touch the MBR and instead install a chain-loaded boot loader in their own partition headers. In this new scheme as all installations share a loader directory no manual configuration has to take place, and all participants implicitly cooperate due to removal of name collisions and can install/remove their own boot menu entries at free will, without interfering with the entries of other installed operating systems.
-* Drop-in directories are otherwise now pretty ubiquitous on Linux as an easy way to extend configuration without having to edit, regenerate or manipulate configuration files. For the sake of uniformity we should do the same for extending the boot menu.
+* Drop-in directories are otherwise now pretty ubiquitous on Linux as an easy way to extend configuration without having to edit, regenerate or manipulate configuration files. For the sake of uniformity, we should do the same for extending the boot menu.
* Userspace code can sanely parse boot loader configuration which is essential with modern BIOSes which do not necessarily initialize USB keyboards anymore during boot, which makes boot menus hard to reach for the user. If userspace code can parse the boot loader configuration, too, this allows for UIs that can select a boot menu item to boot into, before rebooting the machine, thus not requiring interactivity during early boot.
-* To unify and thus simplify configuration of the various boot loaders around, which makes configuration of the boot loading process easier for users, administrators and developers alike
+* To unify and thus simplify configuration of the various boot loaders around, which makes configuration of the boot loading process easier for users, administrators and developers alike.
* For boot loaders with configuration _scripts_ such as grub2, adopting this spec allows for mostly static scripts that are generated only once at first installation, but then do not need to be updated anymore as that is done via drop-in files exclusively.
## Why not simply rely on the EFI boot menu logic?
@@ -25,7 +25,7 @@ Of course, without this specification things already work mostly fine. But here'
The EFI specification provides a boot options logic that can offer similar functionality. Here's why we think that it is not enough for our uses:
* The various EFI implementations implement the boot order/boot item logic to different levels. Some firmware implementations do not offer a boot menu at all and instead unconditionally follow the EFI boot order, booting the first item that is working.
-* If the firmware setup is used to reset all data usually all EFI boot entries are lost, making the system entirely unbootable, as the firmware setups generally do not offer a UI to define additional boot items. By placing the menu item information on disk it is always available, regardless if the BIOS setup data is lost.
+* If the firmware setup is used to reset all data usually all EFI boot entries are lost, making the system entirely unbootable, as the firmware setups generally do not offer a UI to define additional boot items. By placing the menu item information on disk, it is always available, regardless if the BIOS setup data is lost.
* Harddisk images should be moveable between machines and be bootable without requiring explicit EFI variables to be set. This also requires that the list of boot options is defined on disk, and not in EFI variables alone.
* EFI is not universal yet (especially on non-x86 platforms), this specification is useful both for EFI and non-EFI boot loaders.
* Many EFI systems disable USB support during early boot to optimize boot times, thus making keyboard input unavailable in the EFI menu. It is thus useful if the OS UI has a standardized way to discover available boot options which can be booted to.
@@ -36,14 +36,14 @@ Everything described below is located on a placeholder file system `$BOOT`. The
* On disks with MBR disk labels
* If the OS is installed on a disk with MBR disk label, and a partition with the MBR type id of 0xEA already exists it should be used as `$BOOT`.
- * Otherwise, if the the OS is installed on a disk with MBR disk label, a new partition with MBR type id of 0xEA shall be created, of a suitable size (let's say 500MB), and it should be used as `$BOOT`.
+ * Otherwise, if the OS is installed on a disk with MBR disk label, a new partition with MBR type id of 0xEA shall be created, of a suitable size (let's say 500MB), and it should be used as `$BOOT`.
* On disks with GPT disk labels
* If the OS is installed on a disk with GPT disk label, and a partition with the GPT type GUID of bc13c2ff-59e6-4262-a352-b275fd6f7172 already exists, it should be used as `$BOOT`.
* Otherwise, if the OS is installed on a disk with GPT disk label, and an ESP partition (i.e. with the GPT type UID of c12a7328-f81f-11d2-ba4b-00a0c93ec93b) already exists and is large enough (let's say 250MB) and otherwise qualifies, it should be used as `$BOOT`.
* Otherwise, if the OS is installed on a disk with GPT disk label, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) partition with GPT type GUID of bc13c2ff-59e6-4262-a352-b275fd6f7172 shall be created and it should be used as `$BOOT`.
* Otherwise, if the OS is installed on a disk with GPT disk label, and no ESP partition exists yet, a new suitably sized (let's say 500MB) ESP should be created and should be used as `$BOOT`.
-This placeholder file system shall be determined during _installation time_, and an fstab entry maybe be created. It should be mounted to either /boot or /efi. Additional locations like /boot/efi, with /boot being a separate file system, might be supported by implementations. This is not recommended because the mounting of `$BOOT` is then dependent on and requires the mounting of the intermediate file system.
+This placeholder file system shall be determined during _installation time_, and an fstab entry may be created. It should be mounted to either /boot or /efi. Additional locations like /boot/efi, with /boot being a separate file system, might be supported by implementations. This is not recommended because the mounting of `$BOOT` is then dependent on and requires the mounting of the intermediate file system.
**Note:** _`$BOOT` should be considered **shared** among all OS installations of a system. Instead of maintaining one `$BOOT` per installed OS (as `/boot` was traditionally handled), all installed OS share the same place to drop in their boot-time configuration._
@@ -58,23 +58,23 @@ We define two directories below `$BOOT`:
**Note:** _In all cases the /loader directory should be located directly in the root of the file system. Specifically, if `$BOOT` is the ESP, then /loader directory should be located directly in the root directory of the ESP, and not in the EFI/ subdirectory._
-Inside the `$BOOT/loader/entries/` directory each OS vendor may drop one or more configuration snippets with the suffix ".conf", one for each boot menu item. The file name of the file is used for identification of the boot item, but shall never be presented to the user in the UI. The file name may be chosen freely but should be unique enough to avoid clashes between OS installations. More specifically it is suggested to include the machine ID (`/etc/machine-id` or the D-Bus machine ID for OSes that lack `/etc/machine-id`), the kernel version (as returned by `uname -r`) and an OS identifier (The ID field of `/etc/os-release`). Example: `$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
+Inside the `$BOOT/loader/entries/` directory each OS vendor may drop one or more configuration snippets with the suffix ".conf", one for each boot menu item. The file name of the file is used for identification of the boot item but shall never be presented to the user in the UI. The file name may be chosen freely but should be unique enough to avoid clashes between OS installations. More specifically it is suggested to include the machine ID (`/etc/machine-id` or the D-Bus machine ID for OSes that lack `/etc/machine-id`), the kernel version (as returned by `uname -r`) and an OS identifier (The ID field of `/etc/os-release`). Example: `$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
-These configuration snippets shall be Unix-style text files (i.e. line separation with a single newline character), in the UTF-8 encoding. The configuration snippets are loosely inspired on Grub1's configuration syntax. Lines beginning with '#' shall be ignored and used for commenting. The first word of a line is used as key, and shall be separated by a space from its value. The following keys are known:
+These configuration snippets shall be Unix-style text files (i.e. line separation with a single newline character), in the UTF-8 encoding. The configuration snippets are loosely inspired on Grub1's configuration syntax. Lines beginning with '#' shall be ignored and used for commenting. The first word of a line is used as key and shall be separated by a space from its value. The following keys are known:
* `title` shall contain a human readable title string for this menu item. This will be displayed in the boot menu for the item. It is a good idea to initialize this from the `PRETTY_NAME` of `/etc/os-release`. This name should be descriptive and does not have to be unique. If a boot loader discovers two entries with the same title it is a good idea to show more than just the raw title in the UI, for example by appending the `version` field. This field is optional. Example: "Fedora 18 (Spherical Cow)".
-* `version` shall contain a human readable version string for this menu item. This is usually the kernel version and is intended for use by OSes to install multiple kernel versions at the same time with the same `title` field. This field shall be in a syntax that is useful for Debian-style version sorts, so that the boot loader UI can determine the newest version easily and show it first or preselect it automatically. This field is optional. Example: `3.7.2-201.fc18.x86_64`
-* `machine-id` shall contain the machine ID of the OS `/etc/machine-id`. This is useful for boot loaders and applications to filter out boot entries, for example to show only a single newest kernel per OS, or to group items by OS, or to maybe filter out the currently booted OS in UIs that want to show only other installed operating systems. This ID shall be formatted as 32 lower case hexadecimal characters (i.e. without any UUID formatting). This key is optional. Example: `4098b3f648d74c13b1f04ccfba7798e8`
-* `linux` refers to the kernel to spawn, and shall be a path relative to the `$BOOT` directory. It is recommended that every distribution creates a machine id and version specific subdirectory below `$BOOT` and places its kernels and initial RAM disk images there. Example: `/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux`.
-* `initrd` refers to the initrd to use when executing the kernel. This also shall be a path relative to the `$BOOT` directory. This key is optional. This key may appear more than once in which case all specified images are used, in the order they are listed. Example: `6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd`
+* `version` shall contain a human readable version string for this menu item. This is usually the kernel version and is intended for use by OSes to install multiple kernel versions at the same time with the same `title` field. This field shall be in a syntax that is useful for Debian-style version sorts, so that the boot loader UI can determine the newest version easily and show it first or preselect it automatically. This field is optional. Example: `3.7.2-201.fc18.x86_64`.
+* `machine-id` shall contain the machine ID of the OS `/etc/machine-id`. This is useful for boot loaders and applications to filter out boot entries, for example to show only a single newest kernel per OS, or to group items by OS, or to maybe filter out the currently booted OS in UIs that want to show only other installed operating systems. This ID shall be formatted as 32 lower case hexadecimal characters (i.e. without any UUID formatting). This key is optional. Example: `4098b3f648d74c13b1f04ccfba7798e8`.
+* `linux` refers to the kernel to spawn and shall be a path relative to the `$BOOT` directory. It is recommended that every distribution creates a machine id and version specific subdirectory below `$BOOT` and places its kernels and initial RAM disk images there. Example: `/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux`.
+* `initrd` refers to the initrd to use when executing the kernel. This also shall be a path relative to the `$BOOT` directory. This key is optional. This key may appear more than once in which case all specified images are used, in the order they are listed. Example: `6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd`.
* `efi` to spawn arbitrary EFI programs. This also takes a path relative to `$BOOT`. This key is only available on EFI systems.
* `options` shall contain kernel parameters to pass to the Linux kernel to spawn. This key is optional and may appear more than once in which case all specified parameters are used in the order they are listed.
* `devicetree` refers to the binary device tree to use when executing the
kernel. This also shall be a path relative to the `$BOOT` directory. This
-key is optional. Example: `6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.armv7hl/tegra20-paz00.dtb`
+key is optional. Example: `6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.armv7hl/tegra20-paz00.dtb`.
* `architecture` refers to the UEFI architecture this entry is defined for. If specified and this does not match the local UEFI system architecture the entry is hidden.
-Each configuration drop-in snippet must include at least a `linux` or an `efi` key, and is otherwise not valid. Here's an example for a complete drop-in file:
+Each configuration drop-in snippet must include at least a `linux` or an `efi` key and is otherwise not valid. Here's an example for a complete drop-in file:
# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf
title Fedora 19 (Rawhide)
@@ -90,7 +90,7 @@ Note that these configuration snippets may only reference kernels (and EFI progr
### Unified kernel images
-A unified kernel image is a single UEFI executable combining an UEFI stub loader, a kernel image, an initramfs image, and the kernel command line. See the description of the `--uefi` option in [dracut(8)](http://man7.org/linux/man-pages/man8/dracut.8.html). Such images will be searched for under `$BOOT/EFI/Linux`, and must have the extension `.efi`.
+A unified kernel image is a single UEFI executable combining an UEFI stub loader, a kernel image, an initramfs image, and the kernel command line. See the description of the `--uefi` option in [dracut(8)](http://man7.org/linux/man-pages/man8/dracut.8.html). Such images will be searched for under `$BOOT/EFI/Linux` and must have the extension `.efi`.
A valid unified kernel image must contain two PE sections:
@@ -114,21 +114,21 @@ Note that all paths used in the configuration snippets use a Unix-style "/" as p
A _boot loader_ needs a file system driver to discover and read `$BOOT`, then simply reads all files `$BOOT/loader/entries/*.conf`, and populates its boot menu with this. It then extends this with any unified kernel images found in `$BOOT/EFI/Linux`. It may also add additional entries, for example "Reboot into firmware". Optionally it may sort the menu based on the `machine-id` and `version` fields, and possibly others. It uses the file name to identify specific items, for example in case it supports storing away default entry information somewhere. A boot loader should generally not modify these files.
-For "boot loader specification" entries, the _kernel package installer_ installs the kernel and initrd images to `$BOOT` (it is recommended to place these files in a vendor and OS and installation specific directory) and then generates a configuration snippet for it, placing this in `$BOOT/loader/entries/xyz.conf`, with xyz as concatenation of machine id and version information (see above). The files created by a kernel package are private property of the kernel package, and should be removed along with it.
+For "boot loader specification" entries, the _kernel package installer_ installs the kernel and initrd images to `$BOOT` (it is recommended to place these files in a vendor and OS and installation specific directory) and then generates a configuration snippet for it, placing this in `$BOOT/loader/entries/xyz.conf`, with xyz as concatenation of machine id and version information (see above). The files created by a kernel package are private property of the kernel package and should be removed along with it.
-For "unified kernel images", the _kernel install_ creates the combined image and drops it into `$BOOT/EFI/Linux`. This file is also private property of the kernel package, and should be removed along with it.
+For "unified kernel images", the _kernel install_ creates the combined image and drops it into `$BOOT/EFI/Linux`. This file is also private property of the kernel package and should be removed along with it.
A _UI application_ intended to show available boot options shall operate similar to a boot loader, but might apply additional filters, for example by filtering out the booted OS via the machine ID, or by suppressing all but the newest kernel versions.
-An _OS installer_ picks the right place for `$BOOT` as defined above (possibly creating a partition and file system for it), and pre-creates the `/loader/entries/` directory in it. It then installs an appropriate boot loader that can read these snippets. Finally it installs one or more kernel packages.
+An _OS installer_ picks the right place for `$BOOT` as defined above (possibly creating a partition and file system for it) and pre-creates the `/loader/entries/` directory in it. It then installs an appropriate boot loader that can read these snippets. Finally, it installs one or more kernel packages.
## Out of Focus
-There are a couple of items that are out of focus for this specifications:
+There are a couple of items that are out of focus for this specification:
-* If userspace can figure out the available boot options, then this is only useful so much: we'd still need to come up with a way how userspace could communicate to the boot loader the default boot loader entry temporarily or persistently. Defining a common scheme for this is certainly a good idea, but out of focus for this specifications.
-* This specifications is just about "Free" Operating systems. Hooking in other operating systems (like Windows, MacOS) into the boot menu is a different story, and should probably happen outside of this specification. For example, boot loaders might choose to detect other available OSes dynamically at runtime without explicit configuration (like <strike>Gummiboot</strike> systemd-boot does it), or via native configuration (for example via explicit Grub2 configuration generated once at installation).
+* If userspace can figure out the available boot options, then this is only useful so much: we'd still need to come up with a way how userspace could communicate to the boot loader the default boot loader entry temporarily or persistently. Defining a common scheme for this is certainly a good idea, but out of focus for this specification.
+* This specification is just about "Free" Operating systems. Hooking in other operating systems (like Windows and macOS) into the boot menu is a different story and should probably happen outside of this specification. For example, boot loaders might choose to detect other available OSes dynamically at runtime without explicit configuration (like <strike>Gummiboot</strike> systemd-boot does it), or via native configuration (for example via explicit Grub2 configuration generated once at installation).
* This specification leaves undefined what to do about systems which are upgraded from an OS that does not implement this specification. As the previous boot loader logic was largely handled by in distribution-specific ways we probably should leave the upgrade path (and whether there actually is one) to the distributions. The simplest solution might be to simply continue with the old scheme for old installations and use this new scheme only for new installations.
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
index 2d73980f16..bb13cfdbfe 100644
--- a/doc/TRANSIENT-SETTINGS.md
+++ b/doc/TRANSIENT-SETTINGS.md
@@ -256,6 +256,7 @@ All process killing settings are available for transient units:
✓ SendSIGHUP=
✓ KillMode=
✓ KillSignal=
+✓ FinalKillSignal=
```
## Service Unit Settings
diff --git a/hwdb/60-sensor.hwdb b/hwdb/60-sensor.hwdb
index 4b165537a7..fa24282edb 100644
--- a/hwdb/60-sensor.hwdb
+++ b/hwdb/60-sensor.hwdb
@@ -11,6 +11,17 @@
# Match string formats:
# sensor:modalias:<parent device modalias>:dmi:<dmi string>
#
+# The device modalias can be seen in the `modalias` file
+# of the sensor parent, for example:
+# cat /sys/`udevadm info -q path -n /dev/iio:device0`/../modalias
+#
+# The full DMI string of the running machine can be read from
+# /sys/class/dmi/id/modalias
+# That requires a kernel built with CONFIG_DMIID set, which is common.
+# The full DMI string is not needed here and the meaning of individual parts
+# can be seen in the source of the DMIID kernel module
+# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/dmi-id.c
+#
# To add local entries, create a new file
# /etc/udev/hwdb.d/61-sensor-local.hwdb
# and add your rules there. To load the new rules execute (as root):
@@ -259,6 +270,10 @@ sensor:modalias:acpi:BOSC0200:BOSC0200:dmi:*ThinkPadYoga11e3rdGen*
sensor:modalias:acpi:BMA250E*:dmi:bvnLENOVO:*:pvrLenovoMIIX3-1030:*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
+# Miix3-830
+sensor:modalias:acpi:SMO8500*:dmi:bvnLENOVO:*:pvrLenovoMIIX3-830:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
+
# IdeaPad Miix 310 note this only is for BIOS version (bvr) 1HCN4?WW, which has
# a portrait LCD panel, versions with bvr 1HCN3?WW have a landscape panel
sensor:modalias:acpi:KIOX000A*:dmi:bvnLENOVO:bvr1HCN4?WW:*:svnLENOVO:pn80SG:*
diff --git a/man/.dir-locals.el b/man/.dir-locals.el
index 1c2512052d..6115b4e8cf 100644
--- a/man/.dir-locals.el
+++ b/man/.dir-locals.el
@@ -1,8 +1,5 @@
; special .c mode with reduced indentation for man pages
-((nil . ((indent-tabs-mode . nil)
- (tab-width . 8)
- (fill-column . 79)))
- (c-mode . ((fill-column . 80)
+((c-mode . ((fill-column . 80)
(c-basic-offset . 2)
(eval . (c-set-offset 'substatement-open 0))
(eval . (c-set-offset 'statement-case-open 0))
@@ -11,4 +8,7 @@
(eval . (c-set-offset 'arglist-close 0))))
(nxml-mode . ((nxml-child-indent . 2)
(fill-column . 119)))
- (meson-mode . ((meson-indent-basic . 8))))
+ (meson-mode . ((meson-indent-basic . 8)))
+ (nil . ((indent-tabs-mode . nil)
+ (tab-width . 8)
+ (fill-column . 79))))
diff --git a/man/coredumpctl.xml b/man/coredumpctl.xml
index caa1bb1c0f..94d5626fb5 100644
--- a/man/coredumpctl.xml
+++ b/man/coredumpctl.xml
@@ -210,7 +210,8 @@
<varlistentry>
<term><command>info</command></term>
- <listitem><para>Show detailed information about core dumps
+ <listitem><para>Show detailed information about the last core dump
+ or core dumps matching specified characteristics
captured in the journal.</para></listitem>
</varlistentry>
diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml
index e1aabacad2..18a6f5f665 100644
--- a/man/nss-myhostname.xml
+++ b/man/nss-myhostname.xml
@@ -6,7 +6,7 @@
SPDX-License-Identifier: LGPL-2.1+
-->
-<refentry id="nss-myhostname" conditional='ENABLE_MYHOSTNAME'>
+<refentry id="nss-myhostname" conditional='ENABLE_NSS_MYHOSTNAME'>
<refentryinfo>
<title>nss-myhostname</title>
diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml
index 394a905665..d9811b24cc 100644
--- a/man/nss-mymachines.xml
+++ b/man/nss-mymachines.xml
@@ -6,7 +6,7 @@
SPDX-License-Identifier: LGPL-2.1+
-->
-<refentry id="nss-mymachines" conditional='ENABLE_MACHINED'>
+<refentry id="nss-mymachines" conditional='ENABLE_NSS_MYMACHINES'>
<refentryinfo>
<title>nss-mymachines</title>
diff --git a/man/nss-resolve.xml b/man/nss-resolve.xml
index b5dcbbeaca..d747e0b1e5 100644
--- a/man/nss-resolve.xml
+++ b/man/nss-resolve.xml
@@ -6,7 +6,7 @@
SPDX-License-Identifier: LGPL-2.1+
-->
-<refentry id="nss-resolve" conditional='ENABLE_RESOLVE'>
+<refentry id="nss-resolve" conditional='ENABLE_NSS_RESOLVE'>
<refentryinfo>
<title>nss-resolve</title>
diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml
index 5eab995a52..3ce3b282bd 100644
--- a/man/pam_systemd.xml
+++ b/man/pam_systemd.xml
@@ -84,40 +84,43 @@
<varlistentry>
<term><option>class=</option></term>
- <listitem><para>Takes a string argument which sets the session
- class. The XDG_SESSION_CLASS environmental variable takes
- precedence. One of
- <literal>user</literal>,
- <literal>greeter</literal>,
- <literal>lock-screen</literal> or
- <literal>background</literal>. See
- <citerefentry><refentrytitle>sd_session_get_class</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- for details about the session class.</para></listitem>
+ <listitem><para>Takes a string argument which sets the session class. The <varname>XDG_SESSION_CLASS</varname>
+ environment variable (see below) takes precedence. One of <literal>user</literal>, <literal>greeter</literal>,
+ <literal>lock-screen</literal> or <literal>background</literal>. See
+ <citerefentry><refentrytitle>sd_session_get_class</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
+ details about the session class.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>type=</option></term>
- <listitem><para>Takes a string argument which sets the session
- type. The XDG_SESSION_TYPE environmental variable takes
- precedence. One of
- <literal>unspecified</literal>,
- <literal>tty</literal>,
- <literal>x11</literal>,
- <literal>wayland</literal> or
- <literal>mir</literal>. See
- <citerefentry><refentrytitle>sd_session_get_type</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- for details about the session type.</para></listitem>
+ <listitem><para>Takes a string argument which sets the session type. The <varname>XDG_SESSION_TYPE</varname>
+ environment variable (see below) takes precedence. One of <literal>unspecified</literal>,
+ <literal>tty</literal>, <literal>x11</literal>, <literal>wayland</literal> or <literal>mir</literal>. See
+ <citerefentry><refentrytitle>sd_session_get_type</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
+ details about the session type.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>desktop=</option></term>
+
+ <listitem><para>Takes a single, short identifier string for the desktop environment. The
+ <varname>XDG_SESSION_DESKTOP</varname> environment variable (see below) takes precedence. This may be used to
+ indicate the session desktop used, where this applies and if this information is available. For example:
+ <literal>GNOME</literal>, or <literal>KDE</literal>. It is recommended to use the same identifiers and
+ capitalization as for <varname>$XDG_CURRENT_DESKTOP</varname>, as defined by the <ulink
+ url="http://standards.freedesktop.org/desktop-entry-spec/latest/">Desktop Entry
+ Specification</ulink>. (However, note that the option only takes a single item, and not a colon-separated list
+ like <varname>$XDG_CURRENT_DESKTOP</varname>.) See
+ <citerefentry><refentrytitle>sd_session_get_desktop</refentrytitle><manvolnum>3</manvolnum></citerefentry> for
+ further details.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>debug<optional>=</optional></option></term>
- <listitem><para>Takes an optional
- boolean argument. If yes or without
- the argument, the module will log
- debugging information as it
- operates.</para></listitem>
+ <listitem><para>Takes an optional boolean argument. If yes or without the argument, the module will log
+ debugging information as it operates.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
@@ -131,20 +134,20 @@
<refsect1>
<title>Environment</title>
- <para>The following environment variables are set for the
- processes of the user's session:</para>
+ <para>The following environment variables are initialized by the module and available to the processes of the
+ user's session:</para>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>$XDG_SESSION_ID</varname></term>
- <listitem><para>A session identifier, suitable to be used in
- filenames. The string itself should be considered opaque,
- although often it is just the audit session ID as reported by
- <filename>/proc/self/sessionid</filename>. Each ID will be
- assigned only once during machine uptime. It may hence be used
- to uniquely label files or other resources of this
- session.</para></listitem>
+ <listitem><para>A short session identifier, suitable to be used in filenames. The string itself should be
+ considered opaque, although often it is just the audit session ID as reported by
+ <filename>/proc/self/sessionid</filename>. Each ID will be assigned only once during machine uptime. It may
+ hence be used to uniquely label files or other resources of this session. Combine this ID with the boot
+ identifier, as returned by
+ <citerefentry><refentrytitle>sd_id128_get_boot</refentrytitle><manvolnum>3</manvolnum></citerefentry>, for a
+ globally unique identifier for the current session.</para></listitem>
</varlistentry>
<varlistentry>
@@ -174,45 +177,31 @@
</variablelist>
- <para>The following environment variables are read by the module
- and may be used by the PAM service to pass metadata to the
- module:</para>
+ <para>The following environment variables are read by the module and may be used by the PAM service to pass
+ metadata to the module. If these variables are not set when the PAM module is invoked but can be determined
+ otherwise they are set by the module, so that these variables are initialized for the session and applications if
+ known at all.</para>
<variablelist class='environment-variables'>
<varlistentry>
<term><varname>$XDG_SESSION_TYPE</varname></term>
- <listitem><para>The session type. This may be used instead of
- <option>session=</option> on the module parameter line, and is
- usually preferred.</para></listitem>
+ <listitem><para>The session type. This may be used instead of <option>session=</option> on the module parameter
+ line, and is usually preferred.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$XDG_SESSION_CLASS</varname></term>
- <listitem><para>The session class. This may be used instead of
- <option>class=</option> on the module parameter line, and is
- usually preferred.</para></listitem>
+ <listitem><para>The session class. This may be used instead of <option>class=</option> on the module parameter
+ line, and is usually preferred.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$XDG_SESSION_DESKTOP</varname></term>
- <listitem><para>A single, short identifier string for the
- desktop environment. This may be used to indicate the session
- desktop used, where this applies and if this information is
- available. For example: <literal>GNOME</literal>, or
- <literal>KDE</literal>. It is recommended to use the same
- identifiers and capitalization as for
- <varname>$XDG_CURRENT_DESKTOP</varname>, as defined by the
- <ulink
- url="http://standards.freedesktop.org/desktop-entry-spec/latest/">Desktop
- Entry Specification</ulink>. (However, note that
- <varname>$XDG_SESSION_DESKTOP</varname> only takes a single
- item, and not a colon-separated list like
- <varname>$XDG_CURRENT_DESKTOP</varname>.) See
- <citerefentry><refentrytitle>sd_session_get_desktop</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- for more details.</para></listitem>
+ <listitem><para>The desktop identifier. This may be used instead of <option>desktop=</option> on the module
+ parameter line, and is usually preferred.</para></listitem>
</varlistentry>
<varlistentry>
@@ -231,9 +220,9 @@
</varlistentry>
</variablelist>
- <para>If not set, <command>pam_systemd</command> will determine the
- values for <varname>$XDG_SEAT</varname> and <varname>$XDG_VTNR</varname>
- based on the <varname>$DISPLAY</varname> variable.</para>
+ <para>If not set, <command>pam_systemd</command> will initialize
+ <varname>$XDG_SEAT</varname> and <varname>$XDG_VTNR</varname>
+ based on the <varname>$DISPLAY</varname> variable (if the latter is set).</para>
</refsect1>
<refsect1>
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 9673ef8886..305876f72b 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -37,9 +37,9 @@ manpages = [
['modules-load.d', '5', [], 'HAVE_KMOD'],
['networkctl', '1', [], 'ENABLE_NETWORKD'],
['networkd.conf', '5', ['networkd.conf.d'], 'ENABLE_NETWORKD'],
- ['nss-myhostname', '8', ['libnss_myhostname.so.2'], 'ENABLE_MYHOSTNAME'],
- ['nss-mymachines', '8', ['libnss_mymachines.so.2'], 'ENABLE_MACHINED'],
- ['nss-resolve', '8', ['libnss_resolve.so.2'], 'ENABLE_RESOLVE'],
+ ['nss-myhostname', '8', ['libnss_myhostname.so.2'], 'ENABLE_NSS_MYHOSTNAME'],
+ ['nss-mymachines', '8', ['libnss_mymachines.so.2'], 'ENABLE_NSS_MYMACHINES'],
+ ['nss-resolve', '8', ['libnss_resolve.so.2'], 'ENABLE_NSS_RESOLVE'],
['nss-systemd', '8', ['libnss_systemd.so.2'], 'ENABLE_NSS_SYSTEMD'],
['os-release', '5', [], ''],
['pam_systemd', '8', [], 'HAVE_PAM'],
@@ -842,6 +842,7 @@ manpages = [
''],
['udev_new', '3', ['udev_ref', 'udev_unref'], ''],
['udevadm', '8', [], ''],
+ ['user@.service', '5', ['user-runtime-dir@.service'], ''],
['vconsole.conf', '5', [], 'ENABLE_VCONSOLE']
]
# Really, do not edit.
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 3cde402a1b..850135cbc0 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -650,7 +650,7 @@
<variablelist>
<varlistentry>
- <term><command>list-units <optional><replaceable>PATTERN</replaceable>…</optional></command></term>
+ <term><command>list-units</command> <optional><replaceable>PATTERN</replaceable>…</optional></term>
<listitem>
<para>List units that <command>systemd</command> currently has in memory. This includes units that are
@@ -698,7 +698,7 @@ To show all installed unit files use 'systemctl list-unit-files'.
</varlistentry>
<varlistentry>
- <term><command>list-sockets <optional><replaceable>PATTERN</replaceable>…</optional></command></term>
+ <term><command>list-sockets</command> <optional><replaceable>PATTERN</replaceable>…</optional></term>
<listitem>
<para>List socket units currently in memory, ordered by listening address. If one or more
@@ -721,7 +721,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</varlistentry>
<varlistentry>
- <term><command>list-timers <optional><replaceable>PATTERN</replaceable>…</optional></command></term>
+ <term><command>list-timers</command> <optional><replaceable>PATTERN</replaceable>…</optional></term>
<listitem>
<para>List timer units currently in memory, ordered by the time they elapse next. If one or more
@@ -1093,7 +1093,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<variablelist>
<varlistentry>
- <term><command>list-unit-files <optional><replaceable>PATTERN…</replaceable></optional></command></term>
+ <term><command>list-unit-files</command> <optional><replaceable>PATTERN…</replaceable></optional></term>
<listitem>
<para>List unit files installed on the system, in combination with their enablement state (as reported by
@@ -1472,7 +1472,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<variablelist>
<varlistentry>
- <term><command>list-machines <optional><replaceable>PATTERN</replaceable>…</optional></command></term>
+ <term><command>list-machines</command> <optional><replaceable>PATTERN</replaceable>…</optional></term>
<listitem>
<para>List the host and all running local containers with
@@ -1774,7 +1774,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</listitem>
</varlistentry>
<varlistentry>
- <term><command>reboot <optional><replaceable>arg</replaceable></optional></command></term>
+ <term><command>reboot</command> <optional><replaceable>arg</replaceable></optional></term>
<listitem>
<para>Shut down and reboot the system. This is mostly equivalent to <command>systemctl start reboot.target
@@ -1814,7 +1814,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
- <term><command>exit <optional><replaceable>EXIT_CODE</replaceable></optional></command></term>
+ <term><command>exit</command> <optional><replaceable>EXIT_CODE</replaceable></optional></term>
<listitem>
<para>Ask the service manager to quit. This is only supported for user service managers (i.e. in
@@ -1828,7 +1828,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
- <term><command>switch-root <replaceable>ROOT</replaceable> <optional><replaceable>INIT</replaceable></optional></command></term>
+ <term><command>switch-root</command> <replaceable>ROOT</replaceable> <optional><replaceable>INIT</replaceable></optional></term>
<listitem>
<para>Switches to a different root directory and executes a new system manager process below it. This is
diff --git a/man/systemd-run.xml b/man/systemd-run.xml
index 149228ee02..6c15d2d837 100644
--- a/man/systemd-run.xml
+++ b/man/systemd-run.xml
@@ -83,6 +83,16 @@
<replaceable>COMMAND</replaceable> may be omitted. In this case, <command>systemd-run</command> creates only a
<filename>.path</filename>, <filename>.socket</filename>, or <filename>.timer</filename> unit that triggers the
specified unit.</para>
+
+ <para>By default, services created with <command>systemd-run</command> default to the <option>simple</option> type,
+ see the description of <varname>Type=</varname> in
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details. Note that when this type is used the service manager (and thus the <command>systemd-run</command> command)
+ considers service start-up successful as soon as the <function>fork()</function> for the main service process
+ succeeded, i.e. before the <function>execve()</function> is invoked, and thus even if the specified command cannot
+ be started. Consider using the <option>exec</option> service type (i.e. <option>--property=Type=exec</option>) to
+ ensure that <command>systemd-run</command> returns successfully only if the specified command line has been
+ successfully started.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 4cdd85f9ff..a9116ea08f 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -99,11 +99,11 @@
<varlistentry>
<term><varname>CPUAffinity=</varname></term>
- <listitem><para>Configures the initial CPU affinity for the
- init process. Takes a list of CPU indices or ranges separated
- by either whitespace or commas. CPU ranges are specified by
- the lower and upper CPU indices separated by a
- dash.</para></listitem>
+ <listitem><para>Configures the CPU affinity for the service manager as well as the default CPU affinity for all
+ forked off processes. Takes a list of CPU indices or ranges separated by either whitespace or commas. CPU
+ ranges are specified by the lower and upper CPU indices separated by a dash. Individual services may override
+ the CPU affinity for their processes with the <varname>CPUAffinity=</varname> setting in unit files, see
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml
index 2112dea31a..1a42906240 100644
--- a/man/systemd.kill.xml
+++ b/man/systemd.kill.xml
@@ -94,7 +94,8 @@
enabled with <varname>SendSIGHUP=</varname>). If then, after a
delay (configured via the <varname>TimeoutStopSec=</varname>
option), processes still remain, the termination request is
- repeated with the <constant>SIGKILL</constant> signal (unless
+ repeated with the <constant>SIGKILL</constant> signal or the
+ signal specified via <varname>FinalKillSignal=</varname> (unless
this is disabled via the <varname>SendSIGKILL=</varname>
option). See
<citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>
@@ -135,9 +136,27 @@
<varlistentry>
<term><varname>SendSIGKILL=</varname></term>
<listitem><para>Specifies whether to send
- <constant>SIGKILL</constant> to remaining processes after a
- timeout, if the normal shutdown procedure left processes of
- the service around. Takes a boolean value. Defaults to "yes".
+ <constant>SIGKILL</constant> (or the signal specified by
+ <varname>FinalKillSignal=</varname>) to remaining processes
+ after a timeout, if the normal shutdown procedure left
+ processes of the service around. Takes a boolean value.
+ Defaults to "yes".
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>FinalKillSignal=</varname></term>
+ <listitem><para>Specifies which signal to send to remaining
+ processes after a timeout if <varname>SendSIGKILL=</varname>
+ is enabled. The signal configured here should be one that is
+ not typically caught and processed by services (<constant>SIGTERM</constant>
+ is not suitable). Developers can find it useful to use this to
+ generate a coredump to troubleshoot why a service did not
+ terminate upon receiving the initial <constant>SIGTERM</constant>
+ signal. This can be achieved by configuring <varname>LimitCORE=</varname>
+ and setting <varname>FinalKillSignal=</varname> to either
+ <constant>SIGQUIT</constant> or <constant>SIGABRT</constant>
+ Defaults to <constant>SIGKILL</constant>.
</para></listitem>
</varlistentry>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index f14a057280..0cd5385f9b 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -153,77 +153,93 @@
<varlistentry>
<term><varname>Type=</varname></term>
- <listitem><para>Configures the process start-up type for this
- service unit. One of
- <option>simple</option>,
- <option>forking</option>,
- <option>oneshot</option>,
- <option>dbus</option>,
- <option>notify</option> or
- <option>idle</option>.</para>
-
- <para>If set to <option>simple</option> (the default if
- neither <varname>Type=</varname> nor
- <varname>BusName=</varname>, but <varname>ExecStart=</varname>
- are specified), it is expected that the process configured
- with <varname>ExecStart=</varname> is the main process of the
- service. In this mode, if the process offers functionality to
- other processes on the system, its communication channels
- should be installed before the daemon is started up (e.g.
- sockets set up by systemd, via socket activation), as systemd
- will immediately proceed starting follow-up units.</para>
-
- <para>If set to <option>forking</option>, it is expected that
- the process configured with <varname>ExecStart=</varname> will
- call <function>fork()</function> as part of its start-up. The
- parent process is expected to exit when start-up is complete
- and all communication channels are set up. The child continues
- to run as the main daemon process. This is the behavior of
- traditional UNIX daemons. If this setting is used, it is
- recommended to also use the <varname>PIDFile=</varname>
- option, so that systemd can identify the main process of the
- daemon. systemd will proceed with starting follow-up units as
- soon as the parent process exits.</para>
-
- <para>Behavior of <option>oneshot</option> is similar to
- <option>simple</option>; however, it is expected that the
- process has to exit before systemd starts follow-up units.
- <varname>RemainAfterExit=</varname> is particularly useful for
- this type of service. This is the implied default if neither
- <varname>Type=</varname> nor <varname>ExecStart=</varname> are
- specified.</para>
-
- <para>Behavior of <option>dbus</option> is similar to
- <option>simple</option>; however, it is expected that the
- daemon acquires a name on the D-Bus bus, as configured by
- <varname>BusName=</varname>. systemd will proceed with
- starting follow-up units after the D-Bus bus name has been
- acquired. Service units with this option configured implicitly
- gain dependencies on the <filename>dbus.socket</filename>
- unit. This type is the default if <varname>BusName=</varname>
- is specified.</para>
-
- <para>Behavior of <option>notify</option> is similar to
- <option>simple</option>; however, it is expected that the
- daemon sends a notification message via
- <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- or an equivalent call when it has finished starting up.
- systemd will proceed with starting follow-up units after this
- notification message has been sent. If this option is used,
- <varname>NotifyAccess=</varname> (see below) should be set to
- open access to the notification socket provided by systemd. If
- <varname>NotifyAccess=</varname> is missing or set to
- <option>none</option>, it will be forcibly set to
- <option>main</option>. Note that currently
- <varname>Type=</varname><option>notify</option> will not work
- if used in combination with
- <varname>PrivateNetwork=</varname><option>yes</option>.</para>
-
- <para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however, actual execution
- of the service program is delayed until all active jobs are dispatched. This may be used to avoid interleaving
- of output of shell services with the status output on the console. Note that this type is useful only to
- improve console output, it is not useful as a general unit ordering tool, and the effect of this service type
- is subject to a 5s time-out, after which the service program is invoked anyway.</para>
+ <listitem>
+ <para>Configures the process start-up type for this service unit. One of <option>simple</option>,
+ <option>exec</option>, <option>forking</option>, <option>oneshot</option>, <option>dbus</option>,
+ <option>notify</option> or <option>idle</option>:</para>
+
+ <itemizedlist>
+ <listitem><para>If set to <option>simple</option> (the default if <varname>ExecStart=</varname> is
+ specified but neither <varname>Type=</varname> nor <varname>BusName=</varname> are), the service manager
+ will consider the unit started immediately after the main service process has been forked off. It is
+ expected that the process configured with <varname>ExecStart=</varname> is the main process of the
+ service. In this mode, if the process offers functionality to other processes on the system, its
+ communication channels should be installed before the service is started up (e.g. sockets set up by
+ systemd, via socket activation), as the service manager will immediately proceed starting follow-up units,
+ right after creating the main service process, and before executing the service's binary. Note that this
+ means <command>systemctl start</command> command lines for <option>simple</option> services will report
+ success even if the service's binary cannot be invoked successfully (for example because the selected
+ <varname>User=</varname> doesn't exist, or the service binary is missing).</para></listitem>
+
+ <listitem><para>The <option>exec</option> type is similar to <option>simple</option>, but the service
+ manager will consider the unit started immediately after the main service binary has been executed. The service
+ manager will delay starting of follow-up units until that point. (Or in other words:
+ <option>simple</option> proceeds with further jobs right after <function>fork()</function> returns, while
+ <option>exec</option> will not proceed before both <function>fork()</function> and
+ <function>execve()</function> in the service process succeeded.) Note that this means <command>systemctl
+ start</command> command lines for <option>exec</option> services will report failure when the service's
+ binary cannot be invoked successfully (for example because the selected <varname>User=</varname> doesn't
+ exist, or the service binary is missing).</para></listitem>
+
+ <listitem><para>If set to <option>forking</option>, it is expected that the process configured with
+ <varname>ExecStart=</varname> will call <function>fork()</function> as part of its start-up. The parent
+ process is expected to exit when start-up is complete and all communication channels are set up. The child
+ continues to run as the main service process, and the service manager will consider the unit started when
+ the parent process exits. This is the behavior of traditional UNIX services. If this setting is used, it is
+ recommended to also use the <varname>PIDFile=</varname> option, so that systemd can reliably identify the
+ main process of the service. systemd will proceed with starting follow-up units as soon as the parent
+ process exits.</para></listitem>
+
+ <listitem><para>Behavior of <option>oneshot</option> is similar to <option>simple</option>; however, the
+ service manager will consider the unit started after the main process exits. It will then start follow-up
+ units. <varname>RemainAfterExit=</varname> is particularly useful for this type of
+ service. <varname>Type=</varname><option>oneshot</option> is the implied default if neither
+ <varname>Type=</varname> nor <varname>ExecStart=</varname> are specified.</para></listitem>
+
+ <listitem><para>Behavior of <option>dbus</option> is similar to <option>simple</option>; however, it is
+ expected that the service acquires a name on the D-Bus bus, as configured by
+ <varname>BusName=</varname>. systemd will proceed with starting follow-up units after the D-Bus bus name
+ has been acquired. Service units with this option configured implicitly gain dependencies on the
+ <filename>dbus.socket</filename> unit. This type is the default if <varname>BusName=</varname> is
+ specified.</para></listitem>
+
+ <listitem><para>Behavior of <option>notify</option> is similar to <option>exec</option>; however, it is
+ expected that the service sends a notification message via
+ <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> or an
+ equivalent call when it has finished starting up. systemd will proceed with starting follow-up units after
+ this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
+ below) should be set to open access to the notification socket provided by systemd. If
+ <varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
+ <option>main</option>. Note that currently <varname>Type=</varname><option>notify</option> will not work if
+ used in combination with <varname>PrivateNetwork=</varname><option>yes</option>.</para></listitem>
+
+ <listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
+ actual execution of the service program is delayed until all active jobs are dispatched. This may be used
+ to avoid interleaving of output of shell services with the status output on the console. Note that this
+ type is useful only to improve console output, it is not useful as a general unit ordering tool, and the
+ effect of this service type is subject to a 5s time-out, after which the service program is invoked
+ anyway.</para></listitem>
+ </itemizedlist>
+
+ <para>It is generally recommended to use <varname>Type=</varname><option>simple</option> for long-running
+ services whenever possible, as it is the simplest and fastest option. However, as this service type won't
+ propagate service start-up failures and doesn't allow ordering of other units against completion of
+ initialization of the service (which for example is useful if clients need to connect to the service through
+ some form of IPC, and the IPC channel is only established by the service itself — in contrast to doing this
+ ahead of time through socket or bus activation or similar), it might not be sufficient for many cases. If so,
+ <option>notify</option> or <option>dbus</option> (the latter only in case the service provides a D-Bus
+ interface) are the preferred options as they allow service program code to precisely schedule when to
+ consider the service started up successfully and when to proceed with follow-up units. The
+ <option>notify</option> service type requires explicit support in the service codebase (as
+ <function>sd_notify()</function> or an equivalent API needs to be invoked by the service at the appropriate
+ time) — if it's not supported, then <option>forking</option> is an alternative: it supports the traditional
+ UNIX service start-up protocol. Finally, <option>exec</option> might be an option for cases where it is
+ enough to ensure the service binary is invoked, and where the service binary itself executes no or little
+ initialization on its own (and its initialization is unlikely to fail). Note that using any type other than
+ <option>simple</option> possibly delays the boot process, as the service manager needs to wait for service
+ initialization to complete. It is hence recommended not to needlessly use any types other than
+ <option>simple</option>. (Also note it is generally not recommended to use <option>idle</option> or
+ <option>oneshot</option> for long-running services.)</para>
</listitem>
</varlistentry>
diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index fb12805fff..38006c6abd 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -104,942 +104,965 @@
</refsect1>
<refsect1>
- <title>Special System Units</title>
-
- <variablelist>
- <varlistentry>
- <term><filename>-.mount</filename></term>
- <listitem>
- <para>The root mount point, i.e. the mount unit for the <filename>/</filename> path. This unit is
- unconditionally active, during the entire time the system is up, as this mount point is where the basic
- userspace is running from.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><filename>basic.target</filename></term>
- <listitem>
- <para>A special target unit covering basic boot-up.</para>
-
- <para>systemd automatically adds dependency of the type
- <varname>After=</varname> for this target unit to all
- services (except for those with
- <varname>DefaultDependencies=no</varname>).</para>
-
- <para>Usually, this should pull-in all local mount points plus
- <filename>/var</filename>, <filename>/tmp</filename> and
- <filename>/var/tmp</filename>, swap devices, sockets, timers,
- path units and other basic initialization necessary for general
- purpose daemons. The mentioned mount points are special cased
- to allow them to be remote.
- </para>
-
- <para>This target usually does not pull in any non-target units
- directly, but rather does so indirectly via other early boot targets.
- It is instead meant as a synchronization point for late boot
- services. Refer to
- <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>
- for details on the targets involved.
- </para>
-
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>ctrl-alt-del.target</filename></term>
- <listitem>
- <para>systemd starts this target whenever Control+Alt+Del is
- pressed on the console. Usually, this should be aliased
- (symlinked) to <filename>reboot.target</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>cryptsetup.target</filename></term>
- <listitem>
- <para>A target that pulls in setup services for all
- encrypted block devices.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>dbus.service</filename></term>
- <listitem>
- <para>A special unit for the D-Bus bus daemon. As soon as
- this service is fully started up systemd will connect to it
- and register its service.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>dbus.socket</filename></term>
- <listitem>
- <para>A special unit for the D-Bus system bus socket. All
- units with <varname>Type=dbus</varname> automatically gain a
- dependency on this unit.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>default.target</filename></term>
- <listitem>
- <para>The default unit systemd starts at bootup. Usually,
- this should be aliased (symlinked) to
- <filename>multi-user.target</filename> or
- <filename>graphical.target</filename>.</para>
-
- <para>The default unit systemd starts at bootup can be
- overridden with the <varname>systemd.unit=</varname> kernel
- command line option.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>display-manager.service</filename></term>
- <listitem>
- <para>The display manager service. Usually, this should be
- aliased (symlinked) to <filename>gdm.service</filename> or a
- similar display manager service.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>emergency.target</filename></term>
- <listitem>
- <para>A special target unit that starts an emergency shell on the main console. This target does not pull in
- any services or mounts. It is the most minimal version of starting the system in order to acquire an
- interactive shell; the only processes running are usually just the system manager (PID 1) and the shell
- process. This unit is supposed to be used with the kernel command line option
- <varname>systemd.unit=</varname>; it is also used when a file system check on a required file system fails,
- and boot-up cannot continue. Compare with <filename>rescue.target</filename>, which serves a similar purpose,
- but also starts the most basic services and mounts all file systems.</para>
-
- <para>Use the <literal>systemd.unit=emergency.target</literal> kernel command line option to boot into this
- mode. A short alias for this kernel command line option is <literal>emergency</literal>, for compatibility
- with SysV.</para>
-
- <para>In many ways booting into <filename>emergency.target</filename> is similar to the effect of booting
- with <literal>init=/bin/sh</literal> on the kernel command line, except that emergency mode provides you with
- the full system and service manager, and allows starting individual units in order to continue the boot
- process in steps.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>exit.target</filename></term>
- <listitem>
- <para>A special service unit for shutting down the system or
- user service manager. It is equivalent to
- <filename>poweroff.target</filename> on non-container
- systems, and also works in containers.</para>
-
- <para>systemd will start this unit when it receives the
- <constant>SIGTERM</constant> or <constant>SIGINT</constant>
- signal when running as user service daemon.</para>
-
- <para>Normally, this (indirectly) pulls in
- <filename>shutdown.target</filename>, which in turn should be
- conflicted by all units that want to be scheduled for
- shutdown when the service manager starts to exit.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>final.target</filename></term>
- <listitem>
- <para>A special target unit that is used during the shutdown
- logic and may be used to pull in late services after all
- normal services are already terminated and all mounts
- unmounted.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>getty.target</filename></term>
- <listitem>
- <para>A special target unit that pulls in statically
- configured local TTY <filename>getty</filename> instances.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>graphical.target</filename></term>
- <listitem>
- <para>A special target unit for setting up a graphical login
- screen. This pulls in
- <filename>multi-user.target</filename>.</para>
-
- <para>Units that are needed for graphical logins shall add
- <varname>Wants=</varname> dependencies for their unit to
- this unit (or <filename>multi-user.target</filename>) during
- installation. This is best configured via
- <varname>WantedBy=graphical.target</varname> in the unit's
- <literal>[Install]</literal> section.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>hibernate.target</filename></term>
- <listitem>
- <para>A special target unit for hibernating the system. This
- pulls in <filename>sleep.target</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>hybrid-sleep.target</filename></term>
- <listitem>
- <para>A special target unit for hibernating and suspending
- the system at the same time. This pulls in
- <filename>sleep.target</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>suspend-then-hibernate.target</filename></term>
- <listitem>
- <para>A special target unit for suspending the system for a period
- of time, waking it and putting it into hibernate. This pulls in
- <filename>sleep.target</filename>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><filename>halt.target</filename></term>
- <listitem>
- <para>A special target unit for shutting down and halting
- the system. Note that this target is distinct from
- <filename>poweroff.target</filename> in that it generally
- really just halts the system rather than powering it
- down.</para>
-
- <para>Applications wanting to halt the system should not start this unit
- directly, but should instead execute <command>systemctl halt</command>
- (possibly with the <option>--no-block</option> option) or call
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
- <command>org.freedesktop.systemd1.Manager.Halt</command> D-Bus method
- directly.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>init.scope</filename></term>
- <listitem>
- <para>This scope unit is where the system and service manager (PID 1) itself resides. It is active as long as
- the system is running.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>initrd-fs.target</filename></term>
- <listitem>
- <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- automatically adds dependencies of type
- <varname>Before=</varname> to
- <filename>sysroot-usr.mount</filename> and all mount points
- found in <filename>/etc/fstab</filename> that have
- <option>x-initrd.mount</option> and not have
- <option>noauto</option> mount options set.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>initrd-root-device.target</filename></term>
- <listitem>
- <para>A special initrd target unit that is reached when the root filesystem device is available, but before
- it has been mounted.
- <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- and
- <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- automatically setup the appropriate dependencies to make this happen.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>initrd-root-fs.target</filename></term>
- <listitem>
- <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- automatically adds dependencies of type
- <varname>Before=</varname> to the
- <filename>sysroot.mount</filename> unit, which is generated
- from the kernel command line.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>kbrequest.target</filename></term>
- <listitem>
- <para>systemd starts this target whenever Alt+ArrowUp is
- pressed on the console. Note that any user with physical access
- to the machine will be able to do this, without authentication,
- so this should be used carefully.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>kexec.target</filename></term>
- <listitem>
- <para>A special target unit for shutting down and rebooting
- the system via kexec.</para>
-
- <para>Applications wanting to reboot the system should not start this unit
- directly, but should instead execute <command>systemctl kexec</command>
- (possibly with the <option>--no-block</option> option) or call
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
- <command>org.freedesktop.systemd1.Manager.KExec</command> D-Bus method
- directly.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>local-fs.target</filename></term>
- <listitem>
- <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- automatically adds dependencies of type
- <varname>Before=</varname> to all mount units that refer to
- local mount points for this target unit. In addition, it
- adds dependencies of type <varname>Wants=</varname> to this
- target unit for those mounts listed in
- <filename>/etc/fstab</filename> that have the
- <option>auto</option> mount option set.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>machines.target</filename></term>
- <listitem>
- <para>A standard target unit for starting all the containers
- and other virtual machines. See <filename>systemd-nspawn@.service</filename>
- for an example.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>multi-user.target</filename></term>
- <listitem>
- <para>A special target unit for setting up a multi-user
- system (non-graphical). This is pulled in by
- <filename>graphical.target</filename>.</para>
-
- <para>Units that are needed for a multi-user system shall
- add <varname>Wants=</varname> dependencies for their unit to
- this unit during installation. This is best configured via
- <varname>WantedBy=multi-user.target</varname> in the unit's
- <literal>[Install]</literal> section.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>network-online.target</filename></term>
- <listitem>
- <para>Units that strictly require a configured network
- connection should pull in
- <filename>network-online.target</filename> (via a
- <varname>Wants=</varname> type dependency) and order
- themselves after it. This target unit is intended to pull in
- a service that delays further execution until the network is
- sufficiently set up. What precisely this requires is left to
- the implementation of the network managing service.</para>
-
- <para>Note the distinction between this unit and
- <filename>network.target</filename>. This unit is an active
- unit (i.e. pulled in by the consumer rather than the
- provider of this functionality) and pulls in a service which
- possibly adds substantial delays to further execution. In
- contrast, <filename>network.target</filename> is a passive
- unit (i.e. pulled in by the provider of the functionality,
- rather than the consumer) that usually does not delay
- execution much. Usually, <filename>network.target</filename>
- is part of the boot of most systems, while
- <filename>network-online.target</filename> is not, except
- when at least one unit requires it. Also see <ulink
- url="https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget">Running
- Services After the Network is up</ulink> for more
- information.</para>
-
- <para>All mount units for remote network file systems
- automatically pull in this unit, and order themselves after
- it. Note that networking daemons that simply provide
- functionality to other hosts generally do not need to pull
- this in.</para>
-
- <para>systemd automatically adds dependencies of type <varname>Wants=</varname> and <varname>After=</varname>
- for this target unit to all SysV init script service units with an LSB header referring to the
- <literal>$network</literal> facility.</para>
-
- <para>Note that this unit is only useful during the original system start-up logic. After the system has
- completed booting up, it will not track the online state of the system anymore. Due to this it cannot be used
- as a network connection monitor concept, it is purely a one-time system start-up concept.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>paths.target</filename></term>
- <listitem>
- <para>A special target unit that sets up all path units (see
- <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details) that shall be active after boot.</para>
-
- <para>It is recommended that path units installed by
- applications get pulled in via <varname>Wants=</varname>
- dependencies from this unit. This is best configured via a
- <varname>WantedBy=paths.target</varname> in the path unit's
- <literal>[Install]</literal> section.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>poweroff.target</filename></term>
- <listitem>
- <para>A special target unit for shutting down and powering
- off the system.</para>
-
- <para>Applications wanting to power off the system should not start this unit
- directly, but should instead execute <command>systemctl poweroff</command>
- (possibly with the <option>--no-block</option> option) or call
- <citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
- <command>org.freedesktop.login1.Manager.PowerOff</command> D-Bus method
- directly.</para>
-
- <para><filename>runlevel0.target</filename> is an alias for
- this target unit, for compatibility with SysV.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>reboot.target</filename></term>
- <listitem>
- <para>A special target unit for shutting down and rebooting
- the system.</para>
-
- <para>Applications wanting to reboot the system should not start this unit
- directly, but should instead execute <command>systemctl reboot</command>
- (possibly with the <option>--no-block</option> option) or call
- <citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
- <command>org.freedesktop.login1.Manager.Reboot</command> D-Bus method
- directly.</para>
-
- <para><filename>runlevel6.target</filename> is an alias for
- this target unit, for compatibility with SysV.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>remote-cryptsetup.target</filename></term>
- <listitem>
- <para>Similar to <filename>cryptsetup.target</filename>, but for encrypted
- devices which are accessed over the network. It is used for
- <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- entries marked with <option>_netdev</option>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>remote-fs.target</filename></term>
- <listitem>
- <para>Similar to <filename>local-fs.target</filename>, but
- for remote mount points.</para>
-
- <para>systemd automatically adds dependencies of type
- <varname>After=</varname> for this target unit to all SysV
- init script service units with an LSB header referring to
- the <literal>$remote_fs</literal> facility.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>rescue.target</filename></term>
- <listitem>
- <para>A special target unit that pulls in the base system (including system mounts) and spawns a rescue
- shell. Isolate to this target in order to administer the system in single-user mode with all file systems
- mounted but with no services running, except for the most basic. Compare with
- <filename>emergency.target</filename>, which is much more reduced and does not provide the file systems or
- most basic services. Compare with <filename>multi-user.target</filename>, this target could be seen as
- <filename>single-user.target</filename>.</para>
-
- <para><filename>runlevel1.target</filename> is an alias for this target unit, for compatibility with
- SysV.</para>
-
- <para>Use the <literal>systemd.unit=rescue.target</literal> kernel command line option to boot into this
- mode. A short alias for this kernel command line option is <literal>1</literal>, for compatibility with
- SysV.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>runlevel2.target</filename></term>
- <term><filename>runlevel3.target</filename></term>
- <term><filename>runlevel4.target</filename></term>
- <term><filename>runlevel5.target</filename></term>
- <listitem>
- <para>These are targets that are called whenever the SysV
- compatibility code asks for runlevel 2, 3, 4, 5,
- respectively. It is a good idea to make this an alias for
- (i.e. symlink to) <filename>graphical.target</filename>
- (for runlevel 5) or <filename>multi-user.target</filename>
- (the others).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>shutdown.target</filename></term>
- <listitem>
- <para>A special target unit that terminates the services on
- system shutdown.</para>
-
- <para>Services that shall be terminated on system shutdown
- shall add <varname>Conflicts=</varname> and
- <varname>Before=</varname> dependencies to this unit for
- their service unit, which is implicitly done when
- <varname>DefaultDependencies=yes</varname> is set (the
- default).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>sigpwr.target</filename></term>
- <listitem>
- <para>A special target that is started when systemd receives
- the SIGPWR process signal, which is normally sent by the
- kernel or UPS daemons when power fails.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>sleep.target</filename></term>
- <listitem>
- <para>A special target unit that is pulled in by
- <filename>suspend.target</filename>,
- <filename>hibernate.target</filename> and
- <filename>hybrid-sleep.target</filename> and may be used to
- hook units into the sleep state logic.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>slices.target</filename></term>
- <listitem>
- <para>A special target unit that sets up all slice units (see
- <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
- details) that shall be active after boot. By default the generic <filename>system.slice</filename>
- slice unit, as well as the root slice unit <filename>-.slice</filename>, is pulled in and ordered before
- this unit (see below).</para>
-
- <para>It's a good idea to add <varname>WantedBy=slices.target</varname> lines to the <literal>[Install]</literal>
- section of all slices units that may be installed dynamically.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>sockets.target</filename></term>
- <listitem>
- <para>A special target unit that sets up all socket
- units (see
- <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details) that shall be active after boot.</para>
-
- <para>Services that can be socket-activated shall add
- <varname>Wants=</varname> dependencies to this unit for
- their socket unit during installation. This is best
- configured via a <varname>WantedBy=sockets.target</varname>
- in the socket unit's <literal>[Install]</literal>
- section.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>suspend.target</filename></term>
- <listitem>
- <para>A special target unit for suspending the system. This
- pulls in <filename>sleep.target</filename>.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>swap.target</filename></term>
- <listitem>
- <para>Similar to <filename>local-fs.target</filename>, but
- for swap partitions and swap files.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>sysinit.target</filename></term>
- <listitem>
- <para>systemd automatically adds dependencies of the types
- <varname>Requires=</varname> and <varname>After=</varname>
- for this target unit to all services (except for those with
- <varname>DefaultDependencies=no</varname>).</para>
-
- <para>This target pulls in the services required for system
- initialization. System services pulled in by this target should
- declare <varname>DefaultDependencies=no</varname> and specify
- all their dependencies manually, including access to anything
- more than a read only root filesystem. For details on the
- dependencies of this target, refer to
- <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>syslog.socket</filename></term>
- <listitem>
- <para>The socket unit syslog implementations should listen
- on. All userspace log messages will be made available on
- this socket. For more information about syslog integration,
- please consult the <ulink
- url="https://www.freedesktop.org/wiki/Software/systemd/syslog">Syslog
- Interface</ulink> document.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>system-update.target</filename></term>
- <term><filename>system-update-pre.target</filename></term>
- <term><filename>system-update-cleanup.service</filename></term>
- <listitem>
- <para>A special target unit that is used for offline system updates.
- <citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- will redirect the boot process to this target if <filename>/system-update</filename>
- exists. For more information see
- <citerefentry><refentrytitle>systemd.offline-updates</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
- </para>
-
- <para>Updates should happen before the <filename>system-update.target</filename> is reached, and the services
- which implement them should cause the machine to reboot. The main units executing the update should order
- themselves after <filename>system-update-pre.target</filename> but not pull it in. Services which want to run
- during system updates only, but before the actual system update is executed should order themselves before
- this unit and pull it in. As a safety measure, if this does not happen, and
- <filename>/system-update</filename> still exists after <filename>system-update.target</filename> is reached,
- <filename>system-update-cleanup.service</filename> will remove this symlink and reboot the machine.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>timers.target</filename></term>
- <listitem>
- <para>A special target unit that sets up all timer units
- (see
- <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details) that shall be active after boot.</para>
-
- <para>It is recommended that timer units installed by
- applications get pulled in via <varname>Wants=</varname>
- dependencies from this unit. This is best configured via
- <varname>WantedBy=timers.target</varname> in the timer
- unit's <literal>[Install]</literal> section.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>umount.target</filename></term>
- <listitem>
- <para>A special target unit that unmounts all mount and
- automount points on system shutdown.</para>
-
- <para>Mounts that shall be unmounted on system shutdown
- shall add Conflicts dependencies to this unit for their
- mount unit, which is implicitly done when
- <varname>DefaultDependencies=yes</varname> is set (the
- default).</para>
- </listitem>
- </varlistentry>
-
- </variablelist>
- </refsect1>
+ <title>Units managed by the system's service manager</title>
+
+ <refsect2>
+ <title>Special System Units</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>-.mount</filename></term>
+ <listitem>
+ <para>The root mount point, i.e. the mount unit for the <filename>/</filename>
+ path. This unit is unconditionally active, during the entire time the system is up, as
+ this mount point is where the basic userspace is running from.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>basic.target</filename></term>
+ <listitem>
+ <para>A special target unit covering basic boot-up.</para>
+
+ <para>systemd automatically adds dependency of the type
+ <varname>After=</varname> for this target unit to all
+ services (except for those with
+ <varname>DefaultDependencies=no</varname>).</para>
+
+ <para>Usually, this should pull-in all local mount points plus
+ <filename>/var</filename>, <filename>/tmp</filename> and
+ <filename>/var/tmp</filename>, swap devices, sockets, timers,
+ path units and other basic initialization necessary for general
+ purpose daemons. The mentioned mount points are special cased
+ to allow them to be remote.
+ </para>
+
+ <para>This target usually does not pull in any non-target units
+ directly, but rather does so indirectly via other early boot targets.
+ It is instead meant as a synchronization point for late boot
+ services. Refer to
+ <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ for details on the targets involved.
+ </para>
- <refsect1>
- <title>Special System Units for Devices</title>
-
- <para>Some target units are automatically pulled in as devices of
- certain kinds show up in the system. These may be used to
- automatically activate various services based on the specific type
- of the available hardware.</para>
-
- <variablelist>
- <varlistentry>
- <term><filename>bluetooth.target</filename></term>
- <listitem>
- <para>This target is started automatically as soon as a
- Bluetooth controller is plugged in or becomes available at
- boot.</para>
-
- <para>This may be used to pull in Bluetooth management
- daemons dynamically when Bluetooth hardware is found.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>printer.target</filename></term>
- <listitem>
- <para>This target is started automatically as soon as a
- printer is plugged in or becomes available at boot.</para>
-
- <para>This may be used to pull in printer management daemons
- dynamically when printer hardware is found.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>smartcard.target</filename></term>
- <listitem>
- <para>This target is started automatically as soon as a
- smartcard controller is plugged in or becomes available at
- boot.</para>
-
- <para>This may be used to pull in smartcard management
- daemons dynamically when smartcard hardware is found.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>sound.target</filename></term>
- <listitem>
- <para>This target is started automatically as soon as a
- sound card is plugged in or becomes available at
- boot.</para>
-
- <para>This may be used to pull in audio management daemons
- dynamically when audio hardware is found.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>ctrl-alt-del.target</filename></term>
+ <listitem>
+ <para>systemd starts this target whenever Control+Alt+Del is
+ pressed on the console. Usually, this should be aliased
+ (symlinked) to <filename>reboot.target</filename>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>cryptsetup.target</filename></term>
+ <listitem>
+ <para>A target that pulls in setup services for all
+ encrypted block devices.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>dbus.service</filename></term>
+ <listitem>
+ <para>A special unit for the D-Bus bus daemon. As soon as
+ this service is fully started up systemd will connect to it
+ and register its service.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>dbus.socket</filename></term>
+ <listitem>
+ <para>A special unit for the D-Bus system bus socket. All
+ units with <varname>Type=dbus</varname> automatically gain a
+ dependency on this unit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>default.target</filename></term>
+ <listitem>
+ <para>The default unit systemd starts at bootup. Usually,
+ this should be aliased (symlinked) to
+ <filename>multi-user.target</filename> or
+ <filename>graphical.target</filename>.</para>
+
+ <para>The default unit systemd starts at bootup can be
+ overridden with the <varname>systemd.unit=</varname> kernel
+ command line option.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>display-manager.service</filename></term>
+ <listitem>
+ <para>The display manager service. Usually, this should be
+ aliased (symlinked) to <filename>gdm.service</filename> or a
+ similar display manager service.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>emergency.target</filename></term>
+ <listitem>
+ <para>A special target unit that starts an emergency shell on the main console. This
+ target does not pull in any services or mounts. It is the most minimal version of
+ starting the system in order to acquire an interactive shell; the only processes running
+ are usually just the system manager (PID 1) and the shell process. This unit is supposed
+ to be used with the kernel command line option <varname>systemd.unit=</varname>; it is
+ also used when a file system check on a required file system fails, and boot-up cannot
+ continue. Compare with <filename>rescue.target</filename>, which serves a similar
+ purpose, but also starts the most basic services and mounts all file systems.</para>
+
+ <para>Use the <literal>systemd.unit=emergency.target</literal> kernel command line
+ option to boot into this mode. A short alias for this kernel command line option is
+ <literal>emergency</literal>, for compatibility with SysV.</para>
+
+ <para>In many ways booting into <filename>emergency.target</filename> is similar to the
+ effect of booting with <literal>init=/bin/sh</literal> on the kernel command line,
+ except that emergency mode provides you with the full system and service manager, and
+ allows starting individual units in order to continue the boot process in steps.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>exit.target</filename></term>
+ <listitem>
+ <para>A special service unit for shutting down the system or
+ user service manager. It is equivalent to
+ <filename>poweroff.target</filename> on non-container
+ systems, and also works in containers.</para>
+
+ <para>systemd will start this unit when it receives the
+ <constant>SIGTERM</constant> or <constant>SIGINT</constant>
+ signal when running as user service daemon.</para>
+
+ <para>Normally, this (indirectly) pulls in
+ <filename>shutdown.target</filename>, which in turn should be
+ conflicted by all units that want to be scheduled for
+ shutdown when the service manager starts to exit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>final.target</filename></term>
+ <listitem>
+ <para>A special target unit that is used during the shutdown
+ logic and may be used to pull in late services after all
+ normal services are already terminated and all mounts
+ unmounted.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>getty.target</filename></term>
+ <listitem>
+ <para>A special target unit that pulls in statically
+ configured local TTY <filename>getty</filename> instances.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>graphical.target</filename></term>
+ <listitem>
+ <para>A special target unit for setting up a graphical login
+ screen. This pulls in
+ <filename>multi-user.target</filename>.</para>
+
+ <para>Units that are needed for graphical logins shall add
+ <varname>Wants=</varname> dependencies for their unit to
+ this unit (or <filename>multi-user.target</filename>) during
+ installation. This is best configured via
+ <varname>WantedBy=graphical.target</varname> in the unit's
+ <literal>[Install]</literal> section.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>hibernate.target</filename></term>
+ <listitem>
+ <para>A special target unit for hibernating the system. This
+ pulls in <filename>sleep.target</filename>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>hybrid-sleep.target</filename></term>
+ <listitem>
+ <para>A special target unit for hibernating and suspending
+ the system at the same time. This pulls in
+ <filename>sleep.target</filename>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>suspend-then-hibernate.target</filename></term>
+ <listitem>
+ <para>A special target unit for suspending the system for a period
+ of time, waking it and putting it into hibernate. This pulls in
+ <filename>sleep.target</filename>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>halt.target</filename></term>
+ <listitem>
+ <para>A special target unit for shutting down and halting
+ the system. Note that this target is distinct from
+ <filename>poweroff.target</filename> in that it generally
+ really just halts the system rather than powering it
+ down.</para>
+
+ <para>Applications wanting to halt the system should not start this unit
+ directly, but should instead execute <command>systemctl halt</command>
+ (possibly with the <option>--no-block</option> option) or call
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+ <command>org.freedesktop.systemd1.Manager.Halt</command> D-Bus method
+ directly.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>init.scope</filename></term>
+ <listitem>
+ <para>This scope unit is where the system and service manager (PID 1) itself resides. It
+ is active as long as the system is running.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>initrd-fs.target</filename></term>
+ <listitem>
+ <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ automatically adds dependencies of type
+ <varname>Before=</varname> to
+ <filename>sysroot-usr.mount</filename> and all mount points
+ found in <filename>/etc/fstab</filename> that have
+ <option>x-initrd.mount</option> and not have
+ <option>noauto</option> mount options set.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>initrd-root-device.target</filename></term>
+ <listitem>
+ <para>A special initrd target unit that is reached when the root filesystem device is available, but before
+ it has been mounted.
+ <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ automatically setup the appropriate dependencies to make this happen.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>initrd-root-fs.target</filename></term>
+ <listitem>
+ <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ automatically adds dependencies of type
+ <varname>Before=</varname> to the
+ <filename>sysroot.mount</filename> unit, which is generated
+ from the kernel command line.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>kbrequest.target</filename></term>
+ <listitem>
+ <para>systemd starts this target whenever Alt+ArrowUp is
+ pressed on the console. Note that any user with physical access
+ to the machine will be able to do this, without authentication,
+ so this should be used carefully.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>kexec.target</filename></term>
+ <listitem>
+ <para>A special target unit for shutting down and rebooting
+ the system via kexec.</para>
+
+ <para>Applications wanting to reboot the system should not start this unit
+ directly, but should instead execute <command>systemctl kexec</command>
+ (possibly with the <option>--no-block</option> option) or call
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
+ <command>org.freedesktop.systemd1.Manager.KExec</command> D-Bus method
+ directly.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>local-fs.target</filename></term>
+ <listitem>
+ <para><citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ automatically adds dependencies of type
+ <varname>Before=</varname> to all mount units that refer to
+ local mount points for this target unit. In addition, it
+ adds dependencies of type <varname>Wants=</varname> to this
+ target unit for those mounts listed in
+ <filename>/etc/fstab</filename> that have the
+ <option>auto</option> mount option set.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>machines.target</filename></term>
+ <listitem>
+ <para>A standard target unit for starting all the containers
+ and other virtual machines. See <filename>systemd-nspawn@.service</filename>
+ for an example.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>multi-user.target</filename></term>
+ <listitem>
+ <para>A special target unit for setting up a multi-user
+ system (non-graphical). This is pulled in by
+ <filename>graphical.target</filename>.</para>
+
+ <para>Units that are needed for a multi-user system shall
+ add <varname>Wants=</varname> dependencies for their unit to
+ this unit during installation. This is best configured via
+ <varname>WantedBy=multi-user.target</varname> in the unit's
+ <literal>[Install]</literal> section.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>network-online.target</filename></term>
+ <listitem>
+ <para>Units that strictly require a configured network
+ connection should pull in
+ <filename>network-online.target</filename> (via a
+ <varname>Wants=</varname> type dependency) and order
+ themselves after it. This target unit is intended to pull in
+ a service that delays further execution until the network is
+ sufficiently set up. What precisely this requires is left to
+ the implementation of the network managing service.</para>
+
+ <para>Note the distinction between this unit and
+ <filename>network.target</filename>. This unit is an active
+ unit (i.e. pulled in by the consumer rather than the
+ provider of this functionality) and pulls in a service which
+ possibly adds substantial delays to further execution. In
+ contrast, <filename>network.target</filename> is a passive
+ unit (i.e. pulled in by the provider of the functionality,
+ rather than the consumer) that usually does not delay
+ execution much. Usually, <filename>network.target</filename>
+ is part of the boot of most systems, while
+ <filename>network-online.target</filename> is not, except
+ when at least one unit requires it. Also see <ulink
+ url="https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget">Running
+ Services After the Network is up</ulink> for more
+ information.</para>
+
+ <para>All mount units for remote network file systems
+ automatically pull in this unit, and order themselves after
+ it. Note that networking daemons that simply provide
+ functionality to other hosts generally do not need to pull
+ this in.</para>
+
+ <para>systemd automatically adds dependencies of type <varname>Wants=</varname> and
+ <varname>After=</varname> for this target unit to all SysV init script service units
+ with an LSB header referring to the <literal>$network</literal> facility.</para>
+
+ <para>Note that this unit is only useful during the original system start-up
+ logic. After the system has completed booting up, it will not track the online state of
+ the system anymore. Due to this it cannot be used as a network connection monitor
+ concept, it is purely a one-time system start-up concept.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>paths.target</filename></term>
+ <listitem>
+ <para>A special target unit that sets up all path units (see
+ <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details) that shall be active after boot.</para>
+
+ <para>It is recommended that path units installed by
+ applications get pulled in via <varname>Wants=</varname>
+ dependencies from this unit. This is best configured via a
+ <varname>WantedBy=paths.target</varname> in the path unit's
+ <literal>[Install]</literal> section.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>poweroff.target</filename></term>
+ <listitem>
+ <para>A special target unit for shutting down and powering
+ off the system.</para>
+
+ <para>Applications wanting to power off the system should not start this unit
+ directly, but should instead execute <command>systemctl poweroff</command>
+ (possibly with the <option>--no-block</option> option) or call
+ <citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+ <command>org.freedesktop.login1.Manager.PowerOff</command> D-Bus method
+ directly.</para>
+
+ <para><filename>runlevel0.target</filename> is an alias for
+ this target unit, for compatibility with SysV.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>reboot.target</filename></term>
+ <listitem>
+ <para>A special target unit for shutting down and rebooting
+ the system.</para>
+
+ <para>Applications wanting to reboot the system should not start this unit
+ directly, but should instead execute <command>systemctl reboot</command>
+ (possibly with the <option>--no-block</option> option) or call
+ <citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+ <command>org.freedesktop.login1.Manager.Reboot</command> D-Bus method
+ directly.</para>
+
+ <para><filename>runlevel6.target</filename> is an alias for
+ this target unit, for compatibility with SysV.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>remote-cryptsetup.target</filename></term>
+ <listitem>
+ <para>Similar to <filename>cryptsetup.target</filename>, but for encrypted
+ devices which are accessed over the network. It is used for
+ <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ entries marked with <option>_netdev</option>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>remote-fs.target</filename></term>
+ <listitem>
+ <para>Similar to <filename>local-fs.target</filename>, but
+ for remote mount points.</para>
+
+ <para>systemd automatically adds dependencies of type
+ <varname>After=</varname> for this target unit to all SysV
+ init script service units with an LSB header referring to
+ the <literal>$remote_fs</literal> facility.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>rescue.target</filename></term>
+ <listitem>
+ <para>A special target unit that pulls in the base system (including system mounts) and
+ spawns a rescue shell. Isolate to this target in order to administer the system in
+ single-user mode with all file systems mounted but with no services running, except for
+ the most basic. Compare with <filename>emergency.target</filename>, which is much more
+ reduced and does not provide the file systems or most basic services. Compare with
+ <filename>multi-user.target</filename>, this target could be seen as
+ <filename>single-user.target</filename>.</para>
+
+ <para><filename>runlevel1.target</filename> is an alias for this target unit, for
+ compatibility with SysV.</para>
+
+ <para>Use the <literal>systemd.unit=rescue.target</literal> kernel command line option
+ to boot into this mode. A short alias for this kernel command line option is
+ <literal>1</literal>, for compatibility with SysV.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>runlevel2.target</filename></term>
+ <term><filename>runlevel3.target</filename></term>
+ <term><filename>runlevel4.target</filename></term>
+ <term><filename>runlevel5.target</filename></term>
+ <listitem>
+ <para>These are targets that are called whenever the SysV
+ compatibility code asks for runlevel 2, 3, 4, 5,
+ respectively. It is a good idea to make this an alias for
+ (i.e. symlink to) <filename>graphical.target</filename>
+ (for runlevel 5) or <filename>multi-user.target</filename>
+ (the others).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>shutdown.target</filename></term>
+ <listitem>
+ <para>A special target unit that terminates the services on
+ system shutdown.</para>
+
+ <para>Services that shall be terminated on system shutdown
+ shall add <varname>Conflicts=</varname> and
+ <varname>Before=</varname> dependencies to this unit for
+ their service unit, which is implicitly done when
+ <varname>DefaultDependencies=yes</varname> is set (the
+ default).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>sigpwr.target</filename></term>
+ <listitem>
+ <para>A special target that is started when systemd receives
+ the SIGPWR process signal, which is normally sent by the
+ kernel or UPS daemons when power fails.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>sleep.target</filename></term>
+ <listitem>
+ <para>A special target unit that is pulled in by
+ <filename>suspend.target</filename>,
+ <filename>hibernate.target</filename> and
+ <filename>hybrid-sleep.target</filename> and may be used to
+ hook units into the sleep state logic.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>slices.target</filename></term>
+ <listitem>
+ <para>A special target unit that sets up all slice units (see
+ <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details) that shall be active after boot. By default the generic
+ <filename>system.slice</filename> slice unit, as well as the root slice unit
+ <filename>-.slice</filename>, is pulled in and ordered before this unit (see
+ below).</para>
+
+ <para>It's a good idea to add <varname>WantedBy=slices.target</varname> lines to the
+ <literal>[Install]</literal> section of all slices units that may be installed
+ dynamically.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>sockets.target</filename></term>
+ <listitem>
+ <para>A special target unit that sets up all socket
+ units (see
+ <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details) that shall be active after boot.</para>
+
+ <para>Services that can be socket-activated shall add
+ <varname>Wants=</varname> dependencies to this unit for
+ their socket unit during installation. This is best
+ configured via a <varname>WantedBy=sockets.target</varname>
+ in the socket unit's <literal>[Install]</literal>
+ section.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>suspend.target</filename></term>
+ <listitem>
+ <para>A special target unit for suspending the system. This
+ pulls in <filename>sleep.target</filename>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>swap.target</filename></term>
+ <listitem>
+ <para>Similar to <filename>local-fs.target</filename>, but
+ for swap partitions and swap files.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>sysinit.target</filename></term>
+ <listitem>
+ <para>systemd automatically adds dependencies of the types
+ <varname>Requires=</varname> and <varname>After=</varname>
+ for this target unit to all services (except for those with
+ <varname>DefaultDependencies=no</varname>).</para>
+
+ <para>This target pulls in the services required for system
+ initialization. System services pulled in by this target should
+ declare <varname>DefaultDependencies=no</varname> and specify
+ all their dependencies manually, including access to anything
+ more than a read only root filesystem. For details on the
+ dependencies of this target, refer to
+ <citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>syslog.socket</filename></term>
+ <listitem>
+ <para>The socket unit syslog implementations should listen
+ on. All userspace log messages will be made available on
+ this socket. For more information about syslog integration,
+ please consult the <ulink
+ url="https://www.freedesktop.org/wiki/Software/systemd/syslog">Syslog
+ Interface</ulink> document.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>system-update.target</filename></term>
+ <term><filename>system-update-pre.target</filename></term>
+ <term><filename>system-update-cleanup.service</filename></term>
+ <listitem>
+ <para>A special target unit that is used for offline system updates.
+ <citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ will redirect the boot process to this target if <filename>/system-update</filename>
+ exists. For more information see
+ <citerefentry><refentrytitle>systemd.offline-updates</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ </para>
+
+ <para>Updates should happen before the <filename>system-update.target</filename> is
+ reached, and the services which implement them should cause the machine to reboot. The
+ main units executing the update should order themselves after
+ <filename>system-update-pre.target</filename> but not pull it in. Services which want to
+ run during system updates only, but before the actual system update is executed should
+ order themselves before this unit and pull it in. As a safety measure, if this does not
+ happen, and <filename>/system-update</filename> still exists after
+ <filename>system-update.target</filename> is reached,
+ <filename>system-update-cleanup.service</filename> will remove this symlink and reboot
+ the machine.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>timers.target</filename></term>
+ <listitem>
+ <para>A special target unit that sets up all timer units
+ (see
+ <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details) that shall be active after boot.</para>
+
+ <para>It is recommended that timer units installed by
+ applications get pulled in via <varname>Wants=</varname>
+ dependencies from this unit. This is best configured via
+ <varname>WantedBy=timers.target</varname> in the timer
+ unit's <literal>[Install]</literal> section.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>umount.target</filename></term>
+ <listitem>
+ <para>A special target unit that unmounts all mount and
+ automount points on system shutdown.</para>
+
+ <para>Mounts that shall be unmounted on system shutdown
+ shall add Conflicts dependencies to this unit for their
+ mount unit, which is implicitly done when
+ <varname>DefaultDependencies=yes</varname> is set (the
+ default).</para>
+ </listitem>
+ </varlistentry>
- <refsect1>
- <title>Special Passive System Units </title>
-
- <para>A number of special system targets are defined that can be
- used to properly order boot-up of optional services. These targets
- are generally not part of the initial boot transaction, unless
- they are explicitly pulled in by one of the implementing services.
- Note specifically that these <emphasis>passive</emphasis> target
- units are generally not pulled in by the consumer of a service,
- but by the provider of the service. This means: a consuming
- service should order itself after these targets (as appropriate),
- but not pull it in. A providing service should order itself before
- these targets (as appropriate) and pull it in (via a
- <varname>Wants=</varname> type dependency).</para>
-
- <para>Note that these passive units cannot be started manually,
- i.e. <literal>systemctl start time-sync.target</literal> will fail
- with an error. They can only be pulled in by dependency. This is
- enforced since they exist for ordering purposes only and thus are
- not useful as only unit within a transaction.</para>
-
- <variablelist>
- <varlistentry>
- <term><filename>cryptsetup-pre.target</filename></term>
- <listitem>
- <para>This passive target unit may be pulled in by services
- that want to run before any encrypted block device is set
- up. All encrypted block devices are set up after this target
- has been reached. Since the shutdown order is implicitly the
- reverse start-up order between units, this target is
- particularly useful to ensure that a service is shut down
- only after all encrypted block devices are fully
- stopped.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>getty-pre.target</filename></term>
- <listitem>
- <para>A special passive target unit. Users of this target
- are expected to pull it in the boot transaction via
- a dependency (e.g. <varname>Wants=</varname>). Order your
- unit before this unit if you want to make use of the console
- just before <filename>getty</filename> is started.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>local-fs-pre.target</filename></term>
- <listitem>
- <para>This target unit is
- automatically ordered before
- all local mount points marked
- with <option>auto</option>
- (see above). It can be used to
- execute certain units before
- all local mounts.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>network.target</filename></term>
- <listitem>
- <para>This unit is supposed to indicate when network
- functionality is available, but it is only very weakly
- defined what that is supposed to mean, with one exception:
- at shutdown, a unit that is ordered after
- <filename>network.target</filename> will be stopped before
- the network — to whatever level it might be set up then —
- is shut down. It is hence useful when writing service files
- that require network access on shutdown, which should order
- themselves after this target, but not pull it in. Also see
- <ulink url="https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget">Running
- Services After the Network is up</ulink> for more
- information. Also see
- <filename>network-online.target</filename> described
- above.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>network-pre.target</filename></term>
- <listitem>
- <para>This passive target unit may be pulled in by services
- that want to run before any network is set up, for example
- for the purpose of setting up a firewall. All network
- management software orders itself after this target, but
- does not pull it in.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>nss-lookup.target</filename></term>
- <listitem>
- <para>A target that should be used as synchronization point for all host/network name service lookups. Note
- that this is independent of UNIX user/group name lookups for which <filename>nss-user-lookup.target</filename>
- should be used. All services for which the availability of full host/network name resolution is essential
- should be ordered after this target, but not pull it in. systemd automatically adds dependencies of type
- <varname>After=</varname> for this target unit to all SysV init script service units with an LSB header
- referring to the <literal>$named</literal> facility.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>nss-user-lookup.target</filename></term>
- <listitem>
- <para>A target that should be used as synchronization point for all regular UNIX user/group name service
- lookups. Note that this is independent of host/network name lookups for which
- <filename>nss-lookup.target</filename> should be used. All services for which the availability of the full
- user/group database is essential should be ordered after this target, but not pull it in. All services which
- provide parts of the user/group database should be ordered before this target, and pull it in. Note that this
- unit is only relevant for regular users and groups — system users and groups are required to be resolvable
- during earliest boot already, and hence do not need any special ordering against this target.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>remote-fs-pre.target</filename></term>
- <listitem>
- <para>This target unit is automatically ordered before all
- mount point units (see above) and cryptsetup devices
- marked with the <option>_netdev</option>. It can be used to run
- certain units before remote encrypted devices and mounts are established.
- Note that this unit is generally not part of the initial
- transaction, unless the unit that wants to be ordered before
- all remote mounts pulls it in via a
- <varname>Wants=</varname> type dependency. If the unit wants
- to be pulled in by the first remote mount showing up, it
- should use <filename>network-online.target</filename> (see
- above).</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>rpcbind.target</filename></term>
- <listitem>
- <para>The portmapper/rpcbind pulls in this target and orders
- itself before it, to indicate its availability. systemd
- automatically adds dependencies of type
- <varname>After=</varname> for this target unit to all SysV
- init script service units with an LSB header referring to
- the <literal>$portmap</literal> facility.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><filename>time-sync.target</filename></term>
- <listitem>
- <para>Services responsible for synchronizing the system
- clock from a remote source (such as NTP client
- implementations) should pull in this target and order
- themselves before it. All services where correct time is
- essential should be ordered after this unit, but not pull it
- in. systemd automatically adds dependencies of type
- <varname>After=</varname> for this target unit to all SysV
- init script service units with an LSB header referring to
- the <literal>$time</literal> facility. </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
+ </variablelist>
+ </refsect2>
- <refsect1>
- <title>Special User Units</title>
+ <refsect2>
+ <title>Special System Units for Devices</title>
- <para>When systemd runs as a user instance, the following special
- units are available, which have similar definitions as their
- system counterparts:
- <filename>exit.target</filename>,
- <filename>default.target</filename>,
- <filename>shutdown.target</filename>,
- <filename>sockets.target</filename>,
- <filename>timers.target</filename>,
- <filename>paths.target</filename>,
- <filename>bluetooth.target</filename>,
- <filename>printer.target</filename>,
- <filename>smartcard.target</filename>,
- <filename>sound.target</filename>.</para>
- </refsect1>
+ <para>Some target units are automatically pulled in as devices of
+ certain kinds show up in the system. These may be used to
+ automatically activate various services based on the specific type
+ of the available hardware.</para>
- <refsect1>
- <title>Special Passive User Units</title>
-
- <variablelist>
- <varlistentry>
- <term><filename>graphical-session.target</filename></term>
- <listitem>
- <para>This target is active whenever any graphical session is running. It is used to stop user services which
- only apply to a graphical (X, Wayland, etc.) session when the session is terminated. Such services should
- have <literal>PartOf=graphical-session.target</literal> in their <literal>[Unit]</literal> section. A target
- for a particular session (e. g. <filename>gnome-session.target</filename>) starts and stops
- <literal>graphical-session.target</literal> with <literal>BindsTo=graphical-session.target</literal>.</para>
-
- <para>Which services are started by a session target is determined by the <literal>Wants=</literal> and
- <literal>Requires=</literal> dependencies. For services that can be enabled independently, symlinks in
- <literal>.wants/</literal> and <literal>.requires/</literal> should be used, see
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Those
- symlinks should either be shipped in packages, or should be added dynamically after installation, for example
- using <literal>systemctl add-wants</literal>, see
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
- </para>
-
- <example>
- <title>Nautilus as part of a GNOME session</title>
-
- <para><literal>gnome-session.target</literal> pulls in Nautilus as top-level service:</para>
-
- <programlisting>[Unit]
-Description=User systemd services for GNOME graphical session
-Wants=nautilus.service
-BindsTo=graphical-session.target</programlisting>
-
- <para><literal>nautilus.service</literal> gets stopped when the session stops:</para>
-
- <programlisting>[Unit]
-Description=Render the desktop icons with Nautilus
-PartOf=graphical-session.target
-
-[Service]
-…</programlisting>
- </example>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><filename>graphical-session-pre.target</filename></term>
- <listitem>
- <para>This target contains services which set up the environment or global configuration of a graphical
- session, such as SSH/GPG agents (which need to export an environment variable into all desktop processes) or
- migration of obsolete d-conf keys after an OS upgrade (which needs to happen before starting any process that
- might use them). This target must be started before starting a graphical session like
- <filename>gnome-session.target</filename>.</para>
- </listitem>
- </varlistentry>
- </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><filename>bluetooth.target</filename></term>
+ <listitem>
+ <para>This target is started automatically as soon as a
+ Bluetooth controller is plugged in or becomes available at
+ boot.</para>
+ <para>This may be used to pull in Bluetooth management
+ daemons dynamically when Bluetooth hardware is found.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>printer.target</filename></term>
+ <listitem>
+ <para>This target is started automatically as soon as a
+ printer is plugged in or becomes available at boot.</para>
+
+ <para>This may be used to pull in printer management daemons
+ dynamically when printer hardware is found.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>smartcard.target</filename></term>
+ <listitem>
+ <para>This target is started automatically as soon as a
+ smartcard controller is plugged in or becomes available at
+ boot.</para>
+
+ <para>This may be used to pull in smartcard management
+ daemons dynamically when smartcard hardware is found.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>sound.target</filename></term>
+ <listitem>
+ <para>This target is started automatically as soon as a
+ sound card is plugged in or becomes available at
+ boot.</para>
+
+ <para>This may be used to pull in audio management daemons
+ dynamically when audio hardware is found.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>Special Passive System Units </title>
+
+ <para>A number of special system targets are defined that can be
+ used to properly order boot-up of optional services. These targets
+ are generally not part of the initial boot transaction, unless
+ they are explicitly pulled in by one of the implementing services.
+ Note specifically that these <emphasis>passive</emphasis> target
+ units are generally not pulled in by the consumer of a service,
+ but by the provider of the service. This means: a consuming
+ service should order itself after these targets (as appropriate),
+ but not pull it in. A providing service should order itself before
+ these targets (as appropriate) and pull it in (via a
+ <varname>Wants=</varname> type dependency).</para>
+
+ <para>Note that these passive units cannot be started manually,
+ i.e. <literal>systemctl start time-sync.target</literal> will fail
+ with an error. They can only be pulled in by dependency. This is
+ enforced since they exist for ordering purposes only and thus are
+ not useful as only unit within a transaction.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>cryptsetup-pre.target</filename></term>
+ <listitem>
+ <para>This passive target unit may be pulled in by services
+ that want to run before any encrypted block device is set
+ up. All encrypted block devices are set up after this target
+ has been reached. Since the shutdown order is implicitly the
+ reverse start-up order between units, this target is
+ particularly useful to ensure that a service is shut down
+ only after all encrypted block devices are fully
+ stopped.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>getty-pre.target</filename></term>
+ <listitem>
+ <para>A special passive target unit. Users of this target
+ are expected to pull it in the boot transaction via
+ a dependency (e.g. <varname>Wants=</varname>). Order your
+ unit before this unit if you want to make use of the console
+ just before <filename>getty</filename> is started.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>local-fs-pre.target</filename></term>
+ <listitem>
+ <para>This target unit is
+ automatically ordered before
+ all local mount points marked
+ with <option>auto</option>
+ (see above). It can be used to
+ execute certain units before
+ all local mounts.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>network.target</filename></term>
+ <listitem>
+ <para>This unit is supposed to indicate when network
+ functionality is available, but it is only very weakly
+ defined what that is supposed to mean, with one exception:
+ at shutdown, a unit that is ordered after
+ <filename>network.target</filename> will be stopped before
+ the network — to whatever level it might be set up then —
+ is shut down. It is hence useful when writing service files
+ that require network access on shutdown, which should order
+ themselves after this target, but not pull it in. Also see
+ <ulink url="https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget">Running
+ Services After the Network is up</ulink> for more
+ information. Also see
+ <filename>network-online.target</filename> described
+ above.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>network-pre.target</filename></term>
+ <listitem>
+ <para>This passive target unit may be pulled in by services
+ that want to run before any network is set up, for example
+ for the purpose of setting up a firewall. All network
+ management software orders itself after this target, but
+ does not pull it in.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>nss-lookup.target</filename></term>
+ <listitem>
+ <para>A target that should be used as synchronization point for all host/network name
+ service lookups. Note that this is independent of UNIX user/group name lookups for which
+ <filename>nss-user-lookup.target</filename> should be used. All services for which the
+ availability of full host/network name resolution is essential should be ordered after
+ this target, but not pull it in. systemd automatically adds dependencies of type
+ <varname>After=</varname> for this target unit to all SysV init script service units
+ with an LSB header referring to the <literal>$named</literal> facility.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>nss-user-lookup.target</filename></term>
+ <listitem>
+ <para>A target that should be used as synchronization point for all regular UNIX
+ user/group name service lookups. Note that this is independent of host/network name
+ lookups for which <filename>nss-lookup.target</filename> should be used. All services
+ for which the availability of the full user/group database is essential should be
+ ordered after this target, but not pull it in. All services which provide parts of the
+ user/group database should be ordered before this target, and pull it in. Note that this
+ unit is only relevant for regular users and groups — system users and groups are
+ required to be resolvable during earliest boot already, and hence do not need any
+ special ordering against this target.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>remote-fs-pre.target</filename></term>
+ <listitem>
+ <para>This target unit is automatically ordered before all
+ mount point units (see above) and cryptsetup devices
+ marked with the <option>_netdev</option>. It can be used to run
+ certain units before remote encrypted devices and mounts are established.
+ Note that this unit is generally not part of the initial
+ transaction, unless the unit that wants to be ordered before
+ all remote mounts pulls it in via a
+ <varname>Wants=</varname> type dependency. If the unit wants
+ to be pulled in by the first remote mount showing up, it
+ should use <filename>network-online.target</filename> (see
+ above).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>rpcbind.target</filename></term>
+ <listitem>
+ <para>The portmapper/rpcbind pulls in this target and orders
+ itself before it, to indicate its availability. systemd
+ automatically adds dependencies of type
+ <varname>After=</varname> for this target unit to all SysV
+ init script service units with an LSB header referring to
+ the <literal>$portmap</literal> facility.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>time-sync.target</filename></term>
+ <listitem>
+ <para>Services responsible for synchronizing the system
+ clock from a remote source (such as NTP client
+ implementations) should pull in this target and order
+ themselves before it. All services where correct time is
+ essential should be ordered after this unit, but not pull it
+ in. systemd automatically adds dependencies of type
+ <varname>After=</varname> for this target unit to all SysV
+ init script service units with an LSB header referring to
+ the <literal>$time</literal> facility. </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>Special Slice Units</title>
+
+ <para>There are four <literal>.slice</literal> units which form the basis of the hierarchy for
+ assignment of resources for services, users, and virtual machines or containers. See
+ <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ for details about slice units.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>-.slice</filename></term>
+ <listitem>
+ <para>The root slice is the root of the slice hierarchy. It usually does not contain
+ units directly, but may be used to set defaults for the whole tree.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>system.slice</filename></term>
+ <listitem>
+ <para>By default, all system services started by
+ <command>systemd</command> are found in this slice.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>user.slice</filename></term>
+ <listitem>
+ <para>By default, all user processes and services started on
+ behalf of the user, including the per-user systemd instance
+ are found in this slice. This is pulled in by
+ <filename>systemd-logind.service</filename></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>machine.slice</filename></term>
+ <listitem>
+ <para>By default, all virtual machines and containers
+ registered with <command>systemd-machined</command> are
+ found in this slice. This is pulled in by
+ <filename>systemd-machined.service</filename></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
</refsect1>
<refsect1>
- <title>Special Slice Units</title>
-
- <para>There are four <literal>.slice</literal> units which form the basis of the hierarchy for assignment of
- resources for services, users, and virtual machines or containers. See
- <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details about slice
- units.</para>
-
- <variablelist>
- <varlistentry>
- <term><filename>-.slice</filename></term>
- <listitem>
- <para>The root slice is the root of the slice hierarchy. It usually does not contain units directly, but may
- be used to set defaults for the whole tree.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><filename>system.slice</filename></term>
- <listitem>
- <para>By default, all system services started by
- <command>systemd</command> are found in this slice.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><filename>user.slice</filename></term>
- <listitem>
- <para>By default, all user processes and services started on
- behalf of the user, including the per-user systemd instance
- are found in this slice. This is pulled in by
- <filename>systemd-logind.service</filename></para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><filename>machine.slice</filename></term>
- <listitem>
- <para>By default, all virtual machines and containers
- registered with <command>systemd-machined</command> are
- found in this slice. This is pulled in by
- <filename>systemd-machined.service</filename></para>
- </listitem>
- </varlistentry>
- </variablelist>
+ <title>Units managed by the user's service manager</title>
+
+ <refsect2>
+ <title>Special User Units</title>
+
+ <para>When systemd runs as a user instance, the following special
+ units are available, which have similar definitions as their
+ system counterparts:
+ <filename>exit.target</filename>,
+ <filename>default.target</filename>,
+ <filename>shutdown.target</filename>,
+ <filename>sockets.target</filename>,
+ <filename>timers.target</filename>,
+ <filename>paths.target</filename>,
+ <filename>bluetooth.target</filename>,
+ <filename>printer.target</filename>,
+ <filename>smartcard.target</filename>,
+ <filename>sound.target</filename>.</para>
+ </refsect2>
+
+ <refsect2>
+ <title>Special Passive User Units</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>graphical-session.target</filename></term>
+ <listitem>
+ <para>This target is active whenever any graphical session is running. It is used to
+ stop user services which only apply to a graphical (X, Wayland, etc.) session when the
+ session is terminated. Such services should have
+ <literal>PartOf=graphical-session.target</literal> in their <literal>[Unit]</literal>
+ section. A target for a particular session (e. g.
+ <filename>gnome-session.target</filename>) starts and stops
+ <literal>graphical-session.target</literal> with
+ <literal>BindsTo=graphical-session.target</literal>.</para>
+
+ <para>Which services are started by a session target is determined by the
+ <literal>Wants=</literal> and <literal>Requires=</literal> dependencies. For services
+ that can be enabled independently, symlinks in <literal>.wants/</literal> and
+ <literal>.requires/</literal> should be used, see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ Those symlinks should either be shipped in packages, or should be added dynamically
+ after installation, for example using <literal>systemctl add-wants</literal>, see
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+ </para>
+
+ <example>
+ <title>Nautilus as part of a GNOME session</title>
+
+ <para><literal>gnome-session.target</literal> pulls in Nautilus as top-level service:</para>
+
+ <programlisting>[Unit]
+ Description=User systemd services for GNOME graphical session
+ Wants=nautilus.service
+ BindsTo=graphical-session.target</programlisting>
+
+ <para><literal>nautilus.service</literal> gets stopped when the session stops:</para>
+
+ <programlisting>[Unit]
+ Description=Render the desktop icons with Nautilus
+ PartOf=graphical-session.target
+
+ [Service]
+ …</programlisting>
+ </example>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>graphical-session-pre.target</filename></term>
+ <listitem>
+ <para>This target contains services which set up the environment or global configuration
+ of a graphical session, such as SSH/GPG agents (which need to export an environment
+ variable into all desktop processes) or migration of obsolete d-conf keys after an OS
+ upgrade (which needs to happen before starting any process that might use them). This
+ target must be started before starting a graphical session like
+ <filename>gnome-session.target</filename>.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
</refsect1>
<refsect1>
@@ -1052,7 +1075,8 @@ PartOf=graphical-session.target
<citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/user@.service.xml b/man/user@.service.xml
new file mode 100644
index 0000000000..30af3c8bf8
--- /dev/null
+++ b/man/user@.service.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="user@.service">
+ <refentryinfo>
+ <title>user@.service</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>user@.service</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>user@.service</refname>
+ <refname>user-runtime-dir@.service</refname>
+ <refpurpose>System units to manage user processes</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>user@<replaceable>UID</replaceable>.service</filename></para>
+ <para><filename>user-runtime-dir@<replaceable>UID</replaceable>.service</filename></para>
+ <para><filename>user-<replaceable>UID</replaceable>.slice</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>The
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ system manager (PID 1) starts user manager instances as
+ <filename>user@<replaceable>UID</replaceable>.service</filename>, where the user's numerical UID
+ is used as the instance identifier. Each <command>systemd --user</command> instance manages a
+ hierarchy of its own units. See
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
+ a discussion of systemd units and
+ <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for a list of units that form the basis of the unit hierarchies of system and user units.</para>
+
+ <para><filename>user@<replaceable>UID</replaceable>.service</filename> is accompanied by the
+ system unit <filename>user-runtime-dir@<replaceable>UID</replaceable>.service</filename>, which
+ creates the user's runtime directory
+ <filename>/run/user/<replaceable>UID</replaceable></filename>, and then removes it when this
+ unit is stopped.</para>
+
+ <para>User processes may be started by the <filename>user@.service</filename> instance, in which
+ case they will be part of that unit in the system hierarchy. They may also be started elsewhere,
+ for example by
+ <citerefentry><refentrytitle>sshd</refentrytitle><manvolnum>8</manvolnum></citerefentry> or a
+ display manager like <command>gdm</command>, in which case they form a .scope unit (see
+ <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+ Both <filename>user@<replaceable>UID</replaceable>.service</filename> and the scope units are
+ collected under a <filename>user-<replaceable>UID</replaceable>.slice</filename>.</para>
+
+ <para>Individual <filename>user-<replaceable>UID</replaceable>.slice</filename> slices are
+ collected under <filename>user.slice</filename>, see
+ <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Controlling resources for logged-in users</title>
+
+ <para>Options that control resources available to logged-in users can be configured at a few
+ different levels. As described in the previous section, <filename>user.slice</filename> contains
+ processes of all users, so any resource limits on that slice apply to all users together. The
+ usual way to configure them would be through drop-ins, e.g. <filename
+ noindex='true'>/etc/systemd/system/user.slice.d/resources.conf</filename>.
+ </para>
+
+ <para>The processes of a single user are collected under
+ <filename>user-<replaceable>UID</replaceable>.slice</filename>. Resource limits for that user
+ can be configured through drop-ins for that unit, e.g. <filename
+ noindex='true'>/etc/systemd/system/user-1000.slice.d/resources.conf</filename>. If the limits
+ should apply to all users instead, they may be configured through drop-ins for the truncated
+ unit name, <filename>user-.slice</filename>. For example, configuration in <filename
+ noindex='true'>/etc/systemd/system/user-.slice.d/resources.conf</filename> is included in all
+ <filename>user-<replaceable>UID</replaceable>.slice</filename> units, see
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for a discussion of the drop-in mechanism.</para>
+
+ <para>When a user logs in and a .scope unit is created for the session (see previous section),
+ the creation of the scope may be managed through
+ <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ This PAM module communicates with
+ <citerefentry><refentrytitle>systemd-logind</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ to create the session scope and provide access to hardware resources. Resource limits for the
+ scope may be configured through the PAM module configuration, see
+ <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ Configuring them through the normal unit configuration is also possible, but since
+ the name of the slice unit is generally unpredictable, this is less useful.</para>
+
+ <para>In general any resources that apply to units may be set for
+ <filename>user@<replaceable>UID</replaceable>.service</filename> and the slice
+ units discussed above, see
+ <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for an overview.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+ <example>
+ <title>Hierarchy of control groups with two logged in users</title>
+
+ <programlisting>$ systemd-cgls
+Control group /:
+-.slice
+├─user.slice
+│ ├─user-1000.slice
+│ │ ├─user@1000.service
+│ │ │ ├─pulseaudio.service
+│ │ │ │ └─2386 /usr/bin/pulseaudio --daemonize=no
+│ │ │ └─gnome-terminal-server.service
+│ │ │ └─init.scope
+│ │ │ ├─ 4127 /usr/libexec/gnome-terminal-server
+│ │ │ └─ 4198 zsh
+│ │ …
+│ │ └─session-4.scope
+│ │ ├─ 1264 gdm-session-worker [pam/gdm-password]
+│ │ ├─ 2339 /usr/bin/gnome-shell
+│ │ …
+│ │ ├─session-19.scope
+│ │ ├─6497 sshd: zbyszek [priv]
+│ │ ├─6502 sshd: zbyszek@pts/6
+│ │ ├─6509 -zsh
+│ │ └─6602 systemd-cgls --no-pager
+│ …
+│ └─user-1001.slice
+│ ├─session-20.scope
+│ │ ├─6675 sshd: guest [priv]
+│ │ ├─6708 sshd: guest@pts/6
+│ │ └─6717 -bash
+│ └─user@1001.service
+│ ├─init.scope
+│ │ ├─6680 /usr/lib/systemd/systemd --user
+│ │ └─6688 (sd-pam)
+│ └─sleep.service
+│ └─6706 /usr/bin/sleep 30
+…</programlisting>
+ <para>User with UID 1000 is logged in using <command>gdm</command> (<filename
+ noindex='true'>session-4.scope</filename>) and
+ <citerefentry><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ (<filename noindex='true'>session-19.scope</filename>), and also has a user manager instance
+ running (<filename noindex='true'>user@1000.service</filename>). User with UID 1001 is logged
+ in using <command>ssh</command> (<filename noindex='true'>session-20.scope</filename>) and
+ also has a user manager instance running (<filename
+ noindex='true'>user@1001.service</filename>). Those are all (leaf) system units, and form
+ part of the slice hierarchy, with <filename noindex='true'>user-1000.slice</filename> and
+ <filename noindex='true'>user-1001.slice</filename> below <filename
+ noindex='true'>user.slice</filename>. User units are visible below the
+ <filename>user@.service</filename> instances (<filename
+ noindex='true'>pulseaudio.service</filename>, <filename
+ noindex='true'>gnome-terminal-server.service</filename>, <filename
+ noindex='true'>init.scope</filename>, <filename noindex='true'>sleep.service</filename>).
+ </para>
+ </example>
+
+ <example>
+ <title>Default user resource limits</title>
+
+ <programlisting>$ systemctl cat user-1000.slice
+# /usr/lib/systemd/system/user-.slice.d/10-defaults.conf
+# …
+[Unit]
+Description=User Slice of UID %j
+After=systemd-user-sessions.service
+
+[Slice]
+TasksMax=33%</programlisting>
+ <para>The <filename>user-<replaceable>UID</replaceable>.slice</filename> units by default don't
+ have a unit file. The resource limits are set through a drop-in, which can be easily replaced
+ or extended following standard drop-in mechanisms discussed in the first section.</para>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/meson.build b/meson.build
index 84656cdc7e..a123940f10 100644
--- a/meson.build
+++ b/meson.build
@@ -9,7 +9,7 @@ project('systemd', 'c',
'sysconfdir=/etc',
'localstatedir=/var',
],
- meson_version : '>= 0.44',
+ meson_version : '>= 0.46',
)
libsystemd_version = '0.23.0'
@@ -362,6 +362,7 @@ if get_option('buildtype') != 'debug'
endif
add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')
+add_project_link_arguments(cc.get_supported_link_arguments(possible_link_flags), language : 'c')
# "negative" arguments: gcc on purpose does not return an error for "-Wno-"
# arguments, just emits a warning. So test for the "positive" version instead.
@@ -389,18 +390,6 @@ if cc.compiles('''
add_project_arguments('-Werror=shadow', language : 'c')
endif
-link_test_c = files('tools/meson-link-test.c')
-
-foreach arg : possible_link_flags
- have = run_command(check_compilation_sh,
- cc.cmd_array(), '-x', 'c', arg,
- '-include', link_test_c).returncode() == 0
- message('Linking with @0@ supported: @1@'.format(arg, have ? 'yes' : 'no'))
- if have
- add_project_link_arguments(arg, language : 'c')
- endif
-endforeach
-
cpp = ' '.join(cc.cmd_array()) + ' -E'
#####################################################################
@@ -635,52 +624,51 @@ else
endif
time_epoch = get_option('time-epoch')
-if time_epoch == ''
+if time_epoch == -1
NEWS = files('NEWS')
- time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout()
+ time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
endif
-time_epoch = time_epoch.to_int()
conf.set('TIME_EPOCH', time_epoch)
system_uid_max = get_option('system-uid-max')
-if system_uid_max == ''
+if system_uid_max == -1
system_uid_max = run_command(
awk,
'/^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }',
'/etc/login.defs').stdout().strip()
if system_uid_max == ''
- system_uid_max = '999'
+ system_uid_max = 999
+ else
+ system_uid_max = system_uid_max.to_int()
endif
endif
-system_uid_max = system_uid_max.to_int()
conf.set('SYSTEM_UID_MAX', system_uid_max)
substs.set('systemuidmax', system_uid_max)
-message('maximum system UID is @0@'.format(system_uid_max))
system_gid_max = get_option('system-gid-max')
-if system_gid_max == ''
+if system_gid_max == -1
system_gid_max = run_command(
awk,
'/^\s*SYS_GID_MAX\s+/ { gid=$2 } END { print gid }',
'/etc/login.defs').stdout().strip()
if system_gid_max == ''
- system_gid_max = '999'
+ system_gid_max = 999
+ else
+ system_gid_max = system_gid_max.to_int()
endif
endif
-system_gid_max = system_gid_max.to_int()
conf.set('SYSTEM_GID_MAX', system_gid_max)
substs.set('systemgidmax', system_gid_max)
-message('maximum system GID is @0@'.format(system_gid_max))
-dynamic_uid_min = get_option('dynamic-uid-min').to_int()
-dynamic_uid_max = get_option('dynamic-uid-max').to_int()
+dynamic_uid_min = get_option('dynamic-uid-min')
+dynamic_uid_max = get_option('dynamic-uid-max')
conf.set('DYNAMIC_UID_MIN', dynamic_uid_min)
conf.set('DYNAMIC_UID_MAX', dynamic_uid_max)
substs.set('dynamicuidmin', dynamic_uid_min)
substs.set('dynamicuidmax', dynamic_uid_max)
-container_uid_base_min = get_option('container-uid-base-min').to_int()
-container_uid_base_max = get_option('container-uid-base-max').to_int()
+container_uid_base_min = get_option('container-uid-base-min')
+container_uid_base_max = get_option('container-uid-base-max')
conf.set('CONTAINER_UID_BASE_MIN', container_uid_base_min)
conf.set('CONTAINER_UID_BASE_MAX', container_uid_base_max)
substs.set('containeruidbasemin', container_uid_base_min)
@@ -689,41 +677,43 @@ substs.set('containeruidbasemax', container_uid_base_max)
nobody_user = get_option('nobody-user')
nobody_group = get_option('nobody-group')
-getent_result = run_command('getent', 'passwd', '65534')
-if getent_result.returncode() == 0
- name = getent_result.stdout().split(':')[0]
- if name != nobody_user
- warning('\n' +
- 'The local user with the UID 65534 does not match the configured user name "@0@" of the nobody user (its name is @1@).\n'.format(nobody_user, name) +
- 'Your build will result in an user table setup that is incompatible with the local system.')
+if not meson.is_cross_build()
+ getent_result = run_command('getent', 'passwd', '65534')
+ if getent_result.returncode() == 0
+ name = getent_result.stdout().split(':')[0]
+ if name != nobody_user
+ warning('\n' +
+ 'The local user with the UID 65534 does not match the configured user name "@0@" of the nobody user (its name is @1@).\n'.format(nobody_user, name) +
+ 'Your build will result in an user table setup that is incompatible with the local system.')
+ endif
endif
-endif
-id_result = run_command('id', '-u', nobody_user)
-if id_result.returncode() == 0
- id = id_result.stdout().to_int()
- if id != 65534
- warning('\n' +
- 'The local user with the configured user name "@0@" of the nobody user does not have UID 65534 (it has @1@).\n'.format(nobody_user, id) +
- 'Your build will result in an user table setup that is incompatible with the local system.')
+ id_result = run_command('id', '-u', nobody_user)
+ if id_result.returncode() == 0
+ id = id_result.stdout().to_int()
+ if id != 65534
+ warning('\n' +
+ 'The local user with the configured user name "@0@" of the nobody user does not have UID 65534 (it has @1@).\n'.format(nobody_user, id) +
+ 'Your build will result in an user table setup that is incompatible with the local system.')
+ endif
endif
-endif
-getent_result = run_command('getent', 'group', '65534')
-if getent_result.returncode() == 0
- name = getent_result.stdout().split(':')[0]
- if name != nobody_group
- warning('\n' +
- 'The local group with the GID 65534 does not match the configured group name "@0@" of the nobody group (its name is @1@).\n'.format(nobody_group, name) +
- 'Your build will result in an group table setup that is incompatible with the local system.')
+ getent_result = run_command('getent', 'group', '65534')
+ if getent_result.returncode() == 0
+ name = getent_result.stdout().split(':')[0]
+ if name != nobody_group
+ warning('\n' +
+ 'The local group with the GID 65534 does not match the configured group name "@0@" of the nobody group (its name is @1@).\n'.format(nobody_group, name) +
+ 'Your build will result in an group table setup that is incompatible with the local system.')
+ endif
endif
-endif
-id_result = run_command('id', '-g', nobody_group)
-if id_result.returncode() == 0
- id = id_result.stdout().to_int()
- if id != 65534
- warning('\n' +
- 'The local group with the configured group name "@0@" of the nobody group does not have UID 65534 (it has @1@).\n'.format(nobody_group, id) +
- 'Your build will result in an group table setup that is incompatible with the local system.')
+ id_result = run_command('id', '-g', nobody_group)
+ if id_result.returncode() == 0
+ id = id_result.stdout().to_int()
+ if id != 65534
+ warning('\n' +
+ 'The local group with the configured group name "@0@" of the nobody group does not have UID 65534 (it has @1@).\n'.format(nobody_group, id) +
+ 'Your build will result in an group table setup that is incompatible with the local system.')
+ endif
endif
endif
if nobody_user != nobody_group and not (nobody_user == 'nobody' and nobody_group == 'nogroup')
@@ -742,17 +732,15 @@ conf.set('TTY_GID', tty_gid)
substs.set('TTY_GID', tty_gid)
# Ensure provided GID argument is numeric, otherwise fallback to default assignment
-if get_option('users-gid') != ''
- users_gid = get_option('users-gid').to_int()
-else
- users_gid = '-'
-endif
-substs.set('USERS_GID', users_gid)
+users_gid = get_option('users-gid')
+substs.set('USERS_GID', users_gid < 0 ? '-' : users_gid)
conf.set10('ENABLE_ADM_GROUP', get_option('adm-group'))
conf.set10('ENABLE_WHEEL_GROUP', get_option('wheel-group'))
-substs.set('DEV_KVM_MODE', get_option('dev-kvm-mode'))
+dev_kvm_mode = get_option('dev-kvm-mode')
+substs.set('DEV_KVM_MODE', dev_kvm_mode)
+conf.set10('DEV_KVM_UACCESS', dev_kvm_mode != '0666')
substs.set('GROUP_RENDER_MODE', get_option('group-render-mode'))
kill_user_processes = get_option('default-kill-user-processes')
@@ -1216,7 +1204,6 @@ foreach term : ['utmp',
'networkd',
'timedated',
'timesyncd',
- 'myhostname',
'firstboot',
'randomseed',
'backlight',
@@ -1233,12 +1220,39 @@ foreach term : ['utmp',
'smack',
'gshadow',
'idn',
+ 'nss-myhostname',
'nss-systemd']
have = get_option(term)
name = 'ENABLE_' + term.underscorify().to_upper()
conf.set10(name, have)
endforeach
+foreach tuple : [['nss-mymachines', 'machined'],
+ ['nss-resolve', 'resolve']]
+ want = get_option(tuple[0])
+ if want != 'false'
+ have = get_option(tuple[1])
+ if want == 'true' and not have
+ error('@0@ is requested but @1@ is disabled'.format(tuple[0], tuple[1]))
+ endif
+ else
+ have = false
+ endif
+ name = 'ENABLE_' + tuple[0].underscorify().to_upper()
+ conf.set10(name, have)
+endforeach
+
+enable_nss = false
+foreach term : ['ENABLE_NSS_MYHOSTNAME',
+ 'ENABLE_NSS_MYMACHINES',
+ 'ENABLE_NSS_RESOLVE',
+ 'ENABLE_NSS_SYSTEMD']
+ if conf.get(term) == 1
+ enable_nss = true
+ endif
+endforeach
+conf.set10('ENABLE_NSS', enable_nss)
+
conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesyncd'))
want_tests = get_option('tests')
@@ -1274,7 +1288,7 @@ if get_option('efi')
have = true
conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
- conf.set('SD_TPM_PCR', get_option('tpm-pcrindex').to_int())
+ conf.set('SD_TPM_PCR', get_option('tpm-pcrindex'))
else
have = false
endif
@@ -1417,10 +1431,10 @@ test_dlopen = executable(
link_with : [libbasic],
dependencies : [libdl])
-foreach tuple : [['myhostname', 'ENABLE_MYHOSTNAME'],
+foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
['systemd', 'ENABLE_NSS_SYSTEMD'],
- ['mymachines', 'ENABLE_MACHINED'],
- ['resolve', 'ENABLE_RESOLVE']]
+ ['mymachines', 'ENABLE_NSS_MYMACHINES'],
+ ['resolve', 'ENABLE_NSS_RESOLVE']]
condition = tuple[1] == '' or conf.get(tuple[1]) == 1
if condition
@@ -2743,13 +2757,7 @@ foreach tuple : sanitizers
sanitizer = tuple[0]
build = tuple[1]
- have = run_command(check_compilation_sh,
- cc.cmd_array(), '-x', 'c',
- '-fsanitize=@0@'.format(sanitizer),
- '-include', link_test_c).returncode() == 0
- message('@0@ sanitizer supported: @1@'.format(sanitizer, have ? 'yes' : 'no'))
-
- if have
+ if cc.has_link_argument('-fsanitize=@0@'.format(sanitizer))
prev = ''
foreach p : fuzz_regression_tests
b = p.split('/')[-2]
@@ -2870,7 +2878,7 @@ status = [
'debug shell: @0@ @ @1@'.format(get_option('debug-shell'),
get_option('debug-tty')),
'TTY GID: @0@'.format(tty_gid),
- 'users GID: @0@'.format(users_gid),
+ 'users GID: @0@'.format(substs.get('USERS_GID')),
'maximum system UID: @0@'.format(system_uid_max),
'maximum system GID: @0@'.format(system_gid_max),
'minimum dynamic UID: @0@'.format(dynamic_uid_min),
@@ -2946,7 +2954,6 @@ foreach tuple : [
['idn'],
['libidn2'],
['libidn'],
- ['nss-systemd'],
['libiptc'],
['elfutils'],
['binfmt'],
@@ -2981,7 +2988,10 @@ foreach tuple : [
['blkid'],
['dbus'],
['glib'],
- ['nss-myhostname', conf.get('ENABLE_MYHOSTNAME') == 1],
+ ['nss-myhostname', conf.get('ENABLE_NSS_MYHOSTNAME') == 1],
+ ['nss-mymachines', conf.get('ENABLE_NSS_MYMACHINES') == 1],
+ ['nss-resolve', conf.get('ENABLE_NSS_RESOLVE') == 1],
+ ['nss-systemd', conf.get('ENABLE_NSS_SYSTEMD') == 1],
['hwdb'],
['tpm'],
['man pages', want_man],
diff --git a/meson_options.txt b/meson_options.txt
index 0b531d96ca..4fdd0caf4a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -88,8 +88,14 @@ option('timesyncd', type : 'boolean',
description : 'install the systemd-timesyncd daemon')
option('remote', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'support for "journal over the network"')
-option('myhostname', type : 'boolean',
- description : 'nss-myhostname support')
+option('nss-myhostname', type : 'boolean',
+ description : 'install nss-myhostname module')
+option('nss-mymachines', type : 'combo', choices : ['auto', 'true', 'false'],
+ description : 'install nss-mymachines module')
+option('nss-resolve', type : 'combo', choices : ['auto', 'true', 'false'],
+ description : 'install nss-resolve module')
+option('nss-systemd', type : 'boolean',
+ description : 'install nss-systemd module')
option('firstboot', type : 'boolean',
description : 'support for firstboot mechanism')
option('randomseed', type : 'boolean',
@@ -144,28 +150,23 @@ option('compat-gateway-hostname', type : 'boolean', value : 'false',
option('default-hierarchy', type : 'combo',
choices : ['legacy', 'hybrid', 'unified'], value : 'hybrid',
description : 'default cgroup hierarchy')
-option('time-epoch', type : 'string',
+option('time-epoch', type : 'integer', value : '-1',
description : 'time epoch for time clients')
-option('system-uid-max', type : 'string',
+option('system-uid-max', type : 'integer', value : '-1',
description : 'maximum system UID')
-option('system-gid-max', type : 'string',
+option('system-gid-max', type : 'integer', value : '-1',
description : 'maximum system GID')
-option('dynamic-uid-min', type : 'string',
- description : 'minimum dynamic UID',
- value : '61184') # That's → 0x0000EF00 in hex
-option('dynamic-uid-max', type : 'string',
- description : 'maximum dynamic UID',
- value : '65519') # That's → 0x0000FFEF in hex
-option('container-uid-base-min', type : 'string',
- description : 'minimum container UID base',
- value : '524288') # That's → 0x00080000 in hex
-option('container-uid-base-max', type : 'string',
- description : 'maximum container UID base',
- value : '1878982656') # That's → 0x6FFF0000 in hex
-option('tty-gid', type : 'string',
- description : 'the numeric GID of the "tty" group',
- value : '5')
-option('users-gid', type : 'string',
+option('dynamic-uid-min', type : 'integer', value : 0x0000EF00,
+ description : 'minimum dynamic UID')
+option('dynamic-uid-max', type : 'integer', value : 0x0000FFEF,
+ description : 'maximum dynamic UID')
+option('container-uid-base-min', type : 'integer', value : 0x00080000,
+ description : 'minimum container UID base')
+option('container-uid-base-max', type : 'integer', value : 0x6FFF0000,
+ description : 'maximum container UID base')
+option('tty-gid', type : 'integer', value : 5,
+ description : 'the numeric GID of the "tty" group')
+option('users-gid', type : 'integer', value : '-1',
description : 'the numeric GID of the "users" group')
option('adm-group', type : 'boolean',
description : 'the ACL for adm group should be added')
@@ -246,8 +247,6 @@ option('libidn2', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libidn2 support')
option('libidn', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libidn support')
-option('nss-systemd', type : 'boolean',
- description : 'enable nss-systemd')
option('libiptc', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libiptc support')
option('qrencode', type : 'combo', choices : ['auto', 'true', 'false'],
@@ -287,7 +286,7 @@ option('efi-ldsdir', type : 'string',
description : 'path to the EFI lds directory')
option('efi-includedir', type : 'string', value : '/usr/include/efi',
description : 'path to the EFI header directory')
-option('tpm-pcrindex', type : 'string', value : '8',
+option('tpm-pcrindex', type : 'integer', value : 8,
description : 'TPM PCR register number to use')
option('bashcompletiondir', type : 'string',
diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run
index d317466b26..4c60130dfa 100644
--- a/shell-completion/bash/systemd-run
+++ b/shell-completion/bash/systemd-run
@@ -79,8 +79,8 @@ _systemd_run() {
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group=
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth=
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment=
- KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK=
- LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=
+ KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
+ LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=
LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE=
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=
PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory=
diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run
index 0ad4b27a6f..a8a8e6fe34 100644
--- a/shell-completion/zsh/_systemd-run
+++ b/shell-completion/zsh/_systemd-run
@@ -32,8 +32,8 @@ _arguments \
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \
- KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= \
- LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \
+ KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
+ LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \
LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \
PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index ac5c05dd87..b723ebf9bd 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -88,6 +88,12 @@ struct boot_times {
usec_t generators_finish_time;
usec_t unitsload_start_time;
usec_t unitsload_finish_time;
+ usec_t initrd_security_start_time;
+ usec_t initrd_security_finish_time;
+ usec_t initrd_generators_start_time;
+ usec_t initrd_generators_finish_time;
+ usec_t initrd_unitsload_start_time;
+ usec_t initrd_unitsload_finish_time;
/*
* If we're analyzing the user instance, all timestamps will be offset
@@ -289,6 +295,37 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
&times.unitsload_finish_time) < 0)
return -EIO;
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDSecurityStartTimestampMonotonic",
+ &times.initrd_security_start_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDSecurityFinishTimestampMonotonic",
+ &times.initrd_security_finish_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDGeneratorsStartTimestampMonotonic",
+ &times.initrd_generators_start_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDGeneratorsFinishTimestampMonotonic",
+ &times.initrd_generators_finish_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDUnitsLoadStartTimestampMonotonic",
+ &times.initrd_unitsload_start_time);
+ (void) bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "InitRDUnitsLoadFinishTimestampMonotonic",
+ &times.initrd_unitsload_finish_time);
+
if (times.finish_time <= 0) {
log_error("Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
"Please try again later.\n"
@@ -453,6 +490,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL;
_cleanup_(free_host_infop) struct host_info *host;
int r;
@@ -460,7 +498,15 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
if (!host)
return log_oom();
- r = bus_map_all_properties(bus,
+ if (arg_scope != UNIT_FILE_SYSTEM) {
+ r = bus_connect_transport(arg_transport, arg_host, false, &system_bus);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to connect to system bus, ignoring: %m");
+ goto manager;
+ }
+ }
+
+ r = bus_map_all_properties(system_bus ?: bus,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
hostname_map,
@@ -468,9 +514,12 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
&error,
NULL,
host);
- if (r < 0)
- log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s", bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+manager:
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
@@ -543,14 +592,14 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
if (t->kernel_time > 0)
- strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
+ strpcpyf(&ptr, size, "= %s ", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
if (unit_id && activated_time > 0 && activated_time != USEC_INFINITY)
size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id, format_timespan(ts, sizeof(ts), activated_time - t->userspace_time, USEC_PER_MSEC));
else if (unit_id && activated_time == 0)
size = strpcpyf(&ptr, size, "\n%s was never reached", unit_id);
else if (unit_id && activated_time == USEC_INFINITY)
- size = strpcpyf(&ptr, size, "\nCould not get time to reach %s.",unit_id);
+ size = strpcpyf(&ptr, size, "\nCould not get time to reach %s.", unit_id);
else if (!unit_id)
size = strpcpyf(&ptr, size, "\ncould not find default.target");
@@ -585,16 +634,38 @@ static void svg_graph_box(double height, double begin, double end) {
}
}
+static int plot_unit_times(struct unit_times *u, double width, int y) {
+ char ts[FORMAT_TIMESPAN_MAX];
+ bool b;
+
+ if (!u->name)
+ return 0;
+
+ svg_bar("activating", u->activating, u->activated, y);
+ svg_bar("active", u->activated, u->deactivating, y);
+ svg_bar("deactivating", u->deactivating, u->deactivated, y);
+
+ /* place the text on the left if we have passed the half of the svg width */
+ b = u->activating * SCALE_X < width / 2;
+ if (u->time)
+ svg_text(b, u->activating, y, "%s (%s)",
+ u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
+ else
+ svg_text(b, u->activating, y, "%s", u->name);
+
+ return 1;
+}
+
static int analyze_plot(int argc, char *argv[], void *userdata) {
_cleanup_(free_host_infop) struct host_info *host = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(unit_times_freep) struct unit_times *times = NULL;
+ _cleanup_free_ char *pretty_times = NULL;
+ bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM;
struct boot_times *boot;
+ struct unit_times *u;
int n, m = 1, y = 0, r;
- bool use_full_bus = true;
double width;
- _cleanup_free_ char *pretty_times = NULL;
- struct unit_times *u;
r = acquire_bus(&bus, &use_full_bus);
if (r < 0)
@@ -608,7 +679,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
if (n < 0)
return n;
- if (use_full_bus) {
+ if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) {
n = acquire_host_info(bus, &host);
if (n < 0)
return n;
@@ -639,8 +710,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
for (u = times; u->has_data; u++) {
double text_start, text_width;
- if (u->activating < boot->userspace_time ||
- u->activating > boot->finish_time) {
+ if (u->activating > boot->finish_time) {
u->name = mfree(u->name);
continue;
}
@@ -711,7 +781,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
svg("<rect class=\"background\" width=\"100%%\" height=\"100%%\" />\n");
svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
- if (use_full_bus)
+ if (host)
svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>",
isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
strempty(host->hostname),
@@ -741,9 +811,23 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
}
if (boot->initrd_time > 0) {
svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
+ if (boot->initrd_security_start_time < boot->initrd_security_finish_time)
+ svg_bar("security", boot->initrd_security_start_time, boot->initrd_security_finish_time, y);
+ if (boot->initrd_generators_start_time < boot->initrd_generators_finish_time)
+ svg_bar("generators", boot->initrd_generators_start_time, boot->initrd_generators_finish_time, y);
+ if (boot->initrd_unitsload_start_time < boot->initrd_unitsload_finish_time)
+ svg_bar("unitsload", boot->initrd_unitsload_start_time, boot->initrd_unitsload_finish_time, y);
svg_text(true, boot->initrd_time, y, "initrd");
y++;
}
+
+ for (u = times; u->has_data; u++) {
+ if (u->activating >= boot->userspace_time)
+ break;
+
+ y += plot_unit_times(u, width, y);
+ }
+
svg_bar("active", boot->userspace_time, boot->finish_time, y);
svg_bar("security", boot->security_start_time, boot->security_finish_time, y);
svg_bar("generators", boot->generators_start_time, boot->generators_finish_time, y);
@@ -751,26 +835,8 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
svg_text(true, boot->userspace_time, y, "systemd");
y++;
- for (u = times; u->has_data; u++) {
- char ts[FORMAT_TIMESPAN_MAX];
- bool b;
-
- if (!u->name)
- continue;
-
- svg_bar("activating", u->activating, u->activated, y);
- svg_bar("active", u->activated, u->deactivating, y);
- svg_bar("deactivating", u->deactivating, u->deactivated, y);
-
- /* place the text on the left if we have passed the half of the svg width */
- b = u->activating * SCALE_X < width / 2;
- if (u->time)
- svg_text(b, u->activating, y, "%s (%s)",
- u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
- else
- svg_text(b, u->activating, y, "%s", u->name);
- y++;
- }
+ for (; u->has_data; u++)
+ y += plot_unit_times(u, width, y);
svg("</g>\n");
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 6d2490f3d7..efac0b9420 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -28,6 +28,7 @@
#include "device-nodes.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "io-util.h"
#include "macro.h"
#include "missing.h"
@@ -59,23 +60,6 @@ static int validate_subvolume_name(const char *name) {
return 0;
}
-static int open_parent(const char *path, int flags) {
- _cleanup_free_ char *parent = NULL;
- int fd;
-
- assert(path);
-
- parent = dirname_malloc(path);
- if (!parent)
- return -ENOMEM;
-
- fd = open(parent, flags);
- if (fd < 0)
- return -errno;
-
- return fd;
-}
-
static int extract_subvolume_name(const char *path, const char **subvolume) {
const char *fn;
int r;
@@ -144,7 +128,7 @@ int btrfs_subvol_make(const char *path) {
if (r < 0)
return r;
- fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ fd = open_parent(path, O_CLOEXEC, 0);
if (fd < 0)
return fd;
@@ -1283,7 +1267,7 @@ int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
if (r < 0)
return r;
- fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ fd = open_parent(path, O_CLOEXEC, 0);
if (fd < 0)
return fd;
@@ -1723,7 +1707,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
if (r < 0)
return r;
- new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ new_fd = open_parent(new_path, O_CLOEXEC, 0);
if (new_fd < 0)
return new_fd;
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 038ece4b06..daa15dbfcb 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2384,10 +2384,9 @@ int cg_kernel_controllers(Set **ret) {
assert(ret);
- /* Determines the full list of kernel-known controllers. Might
- * include controllers we don't actually support, arbitrary
- * named hierarchies and controllers that aren't currently
- * accessible (because not mounted). */
+ /* Determines the full list of kernel-known controllers. Might include controllers we don't actually support
+ * and controllers that aren't currently accessible (because not mounted). This does not include "name="
+ * pseudo-controllers. */
controllers = set_new(&string_hash_ops);
if (!controllers)
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 6b0bad5b71..20d3f567c9 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1225,9 +1225,13 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
const char *fn;
char *t;
- assert(p);
assert(ret);
+ if (isempty(p))
+ return -EINVAL;
+ if (path_equal(p, "/"))
+ return -EINVAL;
+
/*
* Turns this:
* /foo/bar/waldo
@@ -1258,9 +1262,13 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
uint64_t u;
unsigned i;
- assert(p);
assert(ret);
+ if (isempty(p))
+ return -EINVAL;
+ if (path_equal(p, "/"))
+ return -EINVAL;
+
/*
* Turns this:
* /foo/bar/waldo
@@ -1311,7 +1319,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
r = tmp_dir(&p);
if (r < 0)
return r;
- }
+ } else if (isempty(p))
+ return -EINVAL;
extra = strempty(extra);
@@ -1404,7 +1413,8 @@ int open_tmpfile_unlinkable(const char *directory, int flags) {
r = tmp_dir(&directory);
if (r < 0)
return r;
- }
+ } else if (isempty(directory))
+ return -EINVAL;
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
@@ -1439,22 +1449,14 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
* which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
* "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
- {
- _cleanup_free_ char *dn = NULL;
-
- dn = dirname_malloc(target);
- if (!dn)
- return -ENOMEM;
-
- fd = open(dn, O_TMPFILE|flags, 0640);
- if (fd >= 0) {
- *ret_path = NULL;
- return fd;
- }
-
- log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
+ fd = open_parent(target, O_TMPFILE|flags, 0640);
+ if (fd >= 0) {
+ *ret_path = NULL;
+ return fd;
}
+ log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
+
r = tempfn_random(target, NULL, &tmp);
if (r < 0)
return r;
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 3a8b32d881..aca9921de7 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -1156,7 +1156,7 @@ int unlinkat_deallocate(int fd, const char *name, int flags) {
}
int fsync_directory_of_file(int fd) {
- _cleanup_free_ char *path = NULL, *dn = NULL;
+ _cleanup_free_ char *path = NULL;
_cleanup_close_ int dfd = -1;
int r;
@@ -1182,16 +1182,40 @@ int fsync_directory_of_file(int fd) {
if (!path_is_absolute(path))
return -EINVAL;
- dn = dirname_malloc(path);
- if (!dn)
- return -ENOMEM;
-
- dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ dfd = open_parent(path, O_CLOEXEC, 0);
if (dfd < 0)
- return -errno;
+ return dfd;
if (fsync(dfd) < 0)
return -errno;
return 0;
}
+
+int open_parent(const char *path, int flags, mode_t mode) {
+ _cleanup_free_ char *parent = NULL;
+ int fd;
+
+ if (isempty(path))
+ return -EINVAL;
+ if (path_equal(path, "/")) /* requesting the parent of the root dir is fishy, let's prohibit that */
+ return -EINVAL;
+
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
+
+ /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
+ * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
+
+ if ((flags & O_PATH) == O_PATH)
+ flags |= O_DIRECTORY;
+ else if ((flags & O_TMPFILE) != O_TMPFILE)
+ flags |= O_DIRECTORY|O_RDONLY;
+
+ fd = open(parent, flags, mode);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 28566773c6..754163defd 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -103,3 +103,5 @@ void unlink_tempfilep(char (*p)[]);
int unlinkat_deallocate(int fd, const char *name, int flags);
int fsync_directory_of_file(int fd);
+
+int open_parent(const char *path, int flags, mode_t mode);
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index ebe41a4c6c..54d911b095 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -261,7 +261,7 @@ fallback_fstat:
/* flags can be AT_SYMLINK_FOLLOW or 0 */
int path_is_mount_point(const char *t, const char *root, int flags) {
- _cleanup_free_ char *canonical = NULL, *parent = NULL;
+ _cleanup_free_ char *canonical = NULL;
_cleanup_close_ int fd = -1;
int r;
@@ -283,11 +283,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
t = canonical;
}
- parent = dirname_malloc(t);
- if (!parent)
- return -ENOMEM;
-
- fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH);
+ fd = open_parent(t, O_PATH|O_CLOEXEC, 0);
if (fd < 0)
return -errno;
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 6becf85878..db38f91c83 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -637,6 +637,8 @@ int parse_permille_unbounded(const char *p) {
r = safe_atoi(n, &v);
if (r < 0)
return r;
+ if (v < 0)
+ return -ERANGE;
} else {
pc = endswith(p, "%");
if (!pc)
@@ -657,15 +659,14 @@ int parse_permille_unbounded(const char *p) {
r = safe_atoi(n, &v);
if (r < 0)
return r;
+ if (v < 0)
+ return -ERANGE;
if (v > (INT_MAX - q) / 10)
return -ERANGE;
v = v * 10 + q;
}
- if (v < 0)
- return -ERANGE;
-
return v;
}
diff --git a/src/basic/util.c b/src/basic/util.c
index 8f2d6061da..f951d641d7 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -77,31 +77,6 @@ bool display_is_local(const char *display) {
display[1] <= '9';
}
-int socket_from_display(const char *display, char **path) {
- size_t k;
- char *f, *c;
-
- assert(display);
- assert(path);
-
- if (!display_is_local(display))
- return -EINVAL;
-
- k = strspn(display+1, "0123456789");
-
- f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
- if (!f)
- return -ENOMEM;
-
- c = stpcpy(f, "/tmp/.X11-unix/X");
- memcpy(c, display+1, k);
- c[k] = 0;
-
- *path = f;
-
- return 0;
-}
-
bool kexec_loaded(void) {
_cleanup_free_ char *s = NULL;
@@ -255,6 +230,11 @@ int container_get_leader(const char *machine, pid_t *pid) {
assert(machine);
assert(pid);
+ if (streq(machine, ".host")) {
+ *pid = 1;
+ return 0;
+ }
+
if (!machine_name_is_valid(machine))
return -EINVAL;
diff --git a/src/basic/util.h b/src/basic/util.h
index 9699d228f9..42c262f598 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -50,7 +50,6 @@ static inline const char* enable_disable(bool b) {
bool plymouth_running(void);
bool display_is_local(const char *display) _pure_;
-int socket_from_display(const char *display, char **path);
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c
index b6e3c44283..b8c8070341 100644
--- a/src/boot/efi/measure.c
+++ b/src/boot/efi/measure.c
@@ -1,6 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/*
- */
#if ENABLE_TPM
diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h
index 99cf3b3fbd..e04ee127a3 100644
--- a/src/boot/efi/measure.h
+++ b/src/boot/efi/measure.h
@@ -1,6 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/*
- */
#ifndef __SDBOOT_MEASURE_H
#define __SDBOOT_MEASURE_H
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 8ec1fa7be4..595c9d8a16 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -94,10 +94,6 @@ if have_gnu_efi
endif
endif
- message('efi-libdir: "@0@"'.format(efi_libdir))
- message('efi-ldsdir: "@0@"'.format(efi_ldsdir))
- message('efi-includedir: "@0@"'.format(efi_incdir))
-
compile_args = ['-Wall',
'-Wextra',
'-std=gnu90',
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 4318a054a4..15cdfca2a3 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -3,7 +3,6 @@
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
- *
*/
#include <efi.h>
diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c
index 8b66ef73dc..187fed12b2 100644
--- a/src/core/bpf-firewall.c
+++ b/src/core/bpf-firewall.c
@@ -661,7 +661,6 @@ int bpf_firewall_supported(void) {
* c) the BPF implementation in the kernel supports BPF LPM TRIE maps, which we require
* d) the BPF implementation in the kernel supports BPF_PROG_TYPE_CGROUP_SKB programs, which we require
* e) the BPF implementation in the kernel supports the BPF_PROG_ATTACH call, which we require
- *
*/
if (supported >= 0)
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index 028e7ec1c1..3e2a7694a7 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -12,6 +12,7 @@ const sd_bus_vtable bus_kill_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("FinalKillSignal", "i", bus_property_get_int, offsetof(KillContext, final_kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
@@ -19,6 +20,7 @@ const sd_bus_vtable bus_kill_vtable[] = {
static BUS_DEFINE_SET_TRANSIENT_PARSE(kill_mode, KillMode, kill_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
+static BUS_DEFINE_SET_TRANSIENT_TO_STRING(final_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
int bus_kill_context_set_transient_property(
Unit *u,
@@ -47,5 +49,8 @@ int bus_kill_context_set_transient_property(
if (streq(name, "KillSignal"))
return bus_set_transient_kill_signal(u, name, &c->kill_signal, message, flags, error);
+ if (streq(name, "FinalKillSignal"))
+ return bus_set_transient_final_kill_signal(u, name, &c->final_kill_signal, message, flags, error);
+
return 0;
}
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 4ed68af1e0..c2f82e19de 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -232,7 +232,7 @@ static int property_get_show_status(
assert(reply);
assert(m);
- b = m->show_status > 0;
+ b = IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
return sd_bus_message_append_basic(reply, 'b', &b);
}
@@ -2418,6 +2418,12 @@ const sd_bus_vtable bus_manager_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_GENERATORS_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_START]), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDSecurityStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_SECURITY_START]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDSecurityFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDGeneratorsStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_START]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDGeneratorsFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDUnitsLoadStartTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START]), SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("InitRDUnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
SD_BUS_PROPERTY("NNames", "u", property_get_hashmap_size, offsetof(Manager, units), 0),
diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c
index 76e1124cff..5420db8a87 100644
--- a/src/core/emergency-action.c
+++ b/src/core/emergency-action.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- Copyright © 2012 Michael Olbrich
-***/
#include <sys/reboot.h>
diff --git a/src/core/emergency-action.h b/src/core/emergency-action.h
index 61791f176f..ea6590e78a 100644
--- a/src/core/emergency-action.h
+++ b/src/core/emergency-action.h
@@ -1,10 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- Copyright © 2012 Michael Olbrich
-***/
-
typedef enum EmergencyAction {
EMERGENCY_ACTION_NONE,
EMERGENCY_ACTION_REBOOT,
diff --git a/src/core/execute.c b/src/core/execute.c
index 87add14a73..ed3e1459df 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -148,11 +148,11 @@ static int shift_fds(int fds[], size_t n_fds) {
return 0;
}
-static int flags_fds(const int fds[], size_t n_storage_fds, size_t n_socket_fds, bool nonblock) {
+static int flags_fds(const int fds[], size_t n_socket_fds, size_t n_storage_fds, bool nonblock) {
size_t i, n_fds;
int r;
- n_fds = n_storage_fds + n_socket_fds;
+ n_fds = n_socket_fds + n_storage_fds;
if (n_fds <= 0)
return 0;
@@ -2573,6 +2573,7 @@ static int close_remaining_fds(
const DynamicCreds *dcreds,
int user_lookup_fd,
int socket_fd,
+ int exec_fd,
int *fds, size_t n_fds) {
size_t n_dont_close = 0;
@@ -2589,6 +2590,8 @@ static int close_remaining_fds(
if (socket_fd >= 0)
dont_close[n_dont_close++] = socket_fd;
+ if (exec_fd >= 0)
+ dont_close[n_dont_close++] = exec_fd;
if (n_fds > 0) {
memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
n_dont_close += n_fds;
@@ -2725,16 +2728,17 @@ static int exec_child(
int socket_fd,
int named_iofds[3],
int *fds,
- size_t n_storage_fds,
size_t n_socket_fds,
+ size_t n_storage_fds,
char **files_env,
int user_lookup_fd,
int *exit_status) {
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
- _cleanup_free_ char *home_buffer = NULL;
+ int *fds_with_exec_fd, n_fds_with_exec_fd, r, ngids = 0, exec_fd = -1;
_cleanup_free_ gid_t *supplementary_gids = NULL;
const char *username = NULL, *groupname = NULL;
+ _cleanup_free_ char *home_buffer = NULL;
const char *home = NULL, *shell = NULL;
dev_t journal_stream_dev = 0;
ino_t journal_stream_ino = 0;
@@ -2754,7 +2758,6 @@ static int exec_child(
#endif
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
- int r, ngids = 0;
size_t n_fds;
ExecDirectoryType dt;
int secure_bits;
@@ -2798,8 +2801,8 @@ static int exec_child(
/* In case anything used libc syslog(), close this here, too */
closelog();
- n_fds = n_storage_fds + n_socket_fds;
- r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, fds, n_fds);
+ n_fds = n_socket_fds + n_storage_fds;
+ r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, params->exec_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
@@ -3184,18 +3187,59 @@ static int exec_child(
}
/* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
- * more aggressive this time since socket_fd and the netns fds we don't need anymore. The custom endpoint fd
- * was needed to upload the policy and can now be closed as well. */
- r = close_all_fds(fds, n_fds);
+ * more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
+ * however if we have it as we want to keep it open until the final execve(). */
+
+ if (params->exec_fd >= 0) {
+ exec_fd = params->exec_fd;
+
+ if (exec_fd < 3 + (int) n_fds) {
+ int moved_fd;
+
+ /* Let's move the exec fd far up, so that it's outside of the fd range we want to pass to the
+ * process we are about to execute. */
+
+ moved_fd = fcntl(exec_fd, F_DUPFD_CLOEXEC, 3 + (int) n_fds);
+ if (moved_fd < 0) {
+ *exit_status = EXIT_FDS;
+ return log_unit_error_errno(unit, errno, "Couldn't move exec fd up: %m");
+ }
+
+ safe_close(exec_fd);
+ exec_fd = moved_fd;
+ } else {
+ /* This fd should be FD_CLOEXEC already, but let's make sure. */
+ r = fd_cloexec(exec_fd, true);
+ if (r < 0) {
+ *exit_status = EXIT_FDS;
+ return log_unit_error_errno(unit, r, "Failed to make exec fd FD_CLOEXEC: %m");
+ }
+ }
+
+ fds_with_exec_fd = newa(int, n_fds + 1);
+ memcpy(fds_with_exec_fd, fds, n_fds * sizeof(int));
+ fds_with_exec_fd[n_fds] = exec_fd;
+ n_fds_with_exec_fd = n_fds + 1;
+ } else {
+ fds_with_exec_fd = fds;
+ n_fds_with_exec_fd = n_fds;
+ }
+
+ r = close_all_fds(fds_with_exec_fd, n_fds_with_exec_fd);
if (r >= 0)
r = shift_fds(fds, n_fds);
if (r >= 0)
- r = flags_fds(fds, n_storage_fds, n_socket_fds, context->non_blocking);
+ r = flags_fds(fds, n_socket_fds, n_storage_fds, context->non_blocking);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m");
}
+ /* At this point, the fds we want to pass to the program are all ready and set up, with O_CLOEXEC turned off
+ * and at the right fd numbers. The are no other fds open, with one exception: the exec_fd if it is defined,
+ * and it has O_CLOEXEC set, after all we want it to be closed by the execve(), so that our parent knows we
+ * came this far. */
+
secure_bits = context->secure_bits;
if (needs_sandboxing) {
@@ -3426,10 +3470,35 @@ static int exec_child(
LOG_UNIT_INVOCATION_ID(unit));
}
+ if (exec_fd >= 0) {
+ uint8_t hot = 1;
+
+ /* We have finished with all our initializations. Let's now let the manager know that. From this point
+ * on, if the manager sees POLLHUP on the exec_fd, then execve() was successful. */
+
+ if (write(exec_fd, &hot, sizeof(hot)) < 0) {
+ *exit_status = EXIT_EXEC;
+ return log_unit_error_errno(unit, errno, "Failed to enable exec_fd: %m");
+ }
+ }
+
execve(command->path, final_argv, accum_env);
+ r = -errno;
+
+ if (exec_fd >= 0) {
+ uint8_t hot = 0;
- if (errno == ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
- log_struct_errno(LOG_INFO, errno,
+ /* The execve() failed. This means the exec_fd is still open. Which means we need to tell the manager
+ * that POLLHUP on it no longer means execve() succeeded. */
+
+ if (write(exec_fd, &hot, sizeof(hot)) < 0) {
+ *exit_status = EXIT_EXEC;
+ return log_unit_error_errno(unit, errno, "Failed to disable exec_fd: %m");
+ }
+ }
+
+ if (r == -ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
+ log_struct_errno(LOG_INFO, r,
"MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
LOG_UNIT_ID(unit),
LOG_UNIT_INVOCATION_ID(unit),
@@ -3440,7 +3509,7 @@ static int exec_child(
}
*exit_status = EXIT_EXEC;
- return log_unit_error_errno(unit, errno, "Failed to execute command: %m");
+ return log_unit_error_errno(unit, r, "Failed to execute command: %m");
}
static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
@@ -3468,7 +3537,7 @@ int exec_spawn(Unit *unit,
assert(context);
assert(ret);
assert(params);
- assert(params->fds || (params->n_storage_fds + params->n_socket_fds <= 0));
+ assert(params->fds || (params->n_socket_fds + params->n_storage_fds <= 0));
if (context->std_input == EXEC_INPUT_SOCKET ||
context->std_output == EXEC_OUTPUT_SOCKET ||
@@ -3488,8 +3557,8 @@ int exec_spawn(Unit *unit,
} else {
socket_fd = -1;
fds = params->fds;
- n_storage_fds = params->n_storage_fds;
n_socket_fds = params->n_socket_fds;
+ n_storage_fds = params->n_storage_fds;
}
r = exec_context_named_iofds(context, params, named_iofds);
@@ -3528,8 +3597,8 @@ int exec_spawn(Unit *unit,
socket_fd,
named_iofds,
fds,
- n_storage_fds,
n_socket_fds,
+ n_storage_fds,
files_env,
unit->manager->user_lookup_fds[1],
&exit_status);
diff --git a/src/core/execute.h b/src/core/execute.h
index de44085492..cd5165c2d1 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -86,10 +86,10 @@ struct ExecStatus {
};
typedef enum ExecCommandFlags {
- EXEC_COMMAND_IGNORE_FAILURE = 1,
- EXEC_COMMAND_FULLY_PRIVILEGED = 2,
- EXEC_COMMAND_NO_SETUID = 4,
- EXEC_COMMAND_AMBIENT_MAGIC = 8,
+ EXEC_COMMAND_IGNORE_FAILURE = 1 << 0,
+ EXEC_COMMAND_FULLY_PRIVILEGED = 1 << 1,
+ EXEC_COMMAND_NO_SETUID = 1 << 2,
+ EXEC_COMMAND_AMBIENT_MAGIC = 1 << 3,
} ExecCommandFlags;
struct ExecCommand {
@@ -297,8 +297,8 @@ struct ExecParameters {
int *fds;
char **fd_names;
- size_t n_storage_fds;
size_t n_socket_fds;
+ size_t n_storage_fds;
ExecFlags flags;
bool selinux_context_net:1;
@@ -317,6 +317,9 @@ struct ExecParameters {
int stdin_fd;
int stdout_fd;
int stderr_fd;
+
+ /* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done */
+ int exec_fd;
};
#include "unit.h"
diff --git a/src/core/job.c b/src/core/job.c
index 2f37ff5bac..6c62cdf595 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -1366,7 +1366,6 @@ bool job_may_gc(Job *j) {
* we start + other stop → gc
* we stop + other start → stay
* we stop + other stop → stay
- *
*/
return true;
diff --git a/src/core/kill.c b/src/core/kill.c
index 929eebfe37..73fa556d13 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -9,6 +9,7 @@ void kill_context_init(KillContext *c) {
assert(c);
c->kill_signal = SIGTERM;
+ c->final_kill_signal = SIGKILL;
c->send_sigkill = true;
c->send_sighup = false;
}
@@ -21,10 +22,12 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
fprintf(f,
"%sKillMode: %s\n"
"%sKillSignal: SIG%s\n"
+ "%sFinalKillSignal: SIG%s\n"
"%sSendSIGKILL: %s\n"
"%sSendSIGHUP: %s\n",
prefix, kill_mode_to_string(c->kill_mode),
prefix, signal_to_string(c->kill_signal),
+ prefix, signal_to_string(c->final_kill_signal),
prefix, yes_no(c->send_sigkill),
prefix, yes_no(c->send_sighup));
}
diff --git a/src/core/kill.h b/src/core/kill.h
index 2d6aa943a6..f4e312d75a 100644
--- a/src/core/kill.h
+++ b/src/core/kill.h
@@ -21,6 +21,7 @@ typedef enum KillMode {
struct KillContext {
KillMode kill_mode;
int kill_signal;
+ int final_kill_signal;
bool send_sigkill;
bool send_sighup;
};
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 290e8001d8..7a276ea3c8 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -151,7 +151,8 @@ m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup)
$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
-$1.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal)'
+$1.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal)
+$1.FinalKillSignal, config_parse_signal, 0, offsetof($1, kill_context.final_kill_signal)'
)m4_dnl
m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
`$1.Slice, config_parse_unit_slice, 0, 0
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 89b7bd8d09..908d16c9f2 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3013,13 +3013,13 @@ int config_parse_cpu_quota(
return 0;
}
- r = parse_percent_unbounded(rvalue);
+ r = parse_permille_unbounded(rvalue);
if (r <= 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue);
return 0;
}
- c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
+ c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U;
return 0;
}
@@ -3041,7 +3041,7 @@ int config_parse_memory_limit(
if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
- r = parse_percent(rvalue);
+ r = parse_permille(rvalue);
if (r < 0) {
r = parse_size(rvalue, 1024, &bytes);
if (r < 0) {
@@ -3049,7 +3049,7 @@ int config_parse_memory_limit(
return 0;
}
} else
- bytes = physical_memory_scale(r, 100U);
+ bytes = physical_memory_scale(r, 1000U);
if (bytes >= UINT64_MAX ||
(bytes <= 0 && !streq(lvalue, "MemorySwapMax"))) {
@@ -3102,7 +3102,7 @@ int config_parse_tasks_max(
return 0;
}
- r = parse_percent(rvalue);
+ r = parse_permille(rvalue);
if (r < 0) {
r = safe_atou64(rvalue, &v);
if (r < 0) {
@@ -3110,7 +3110,7 @@ int config_parse_tasks_max(
return 0;
}
} else
- v = system_tasks_max_scale(r, 100U);
+ v = system_tasks_max_scale(r, 1000U);
if (v <= 0 || v >= UINT64_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue);
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index dad281ef72..1cb5ccadf6 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -39,6 +39,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
CONFIG_PARSER_PROTOTYPE(config_parse_kill_signal);
+CONFIG_PARSER_PROTOTYPE(config_parse_final_kill_signal);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
CONFIG_PARSER_PROTOTYPE(config_parse_trigger_unit);
diff --git a/src/core/main.c b/src/core/main.c
index 6bffd6f362..c8788b8e8a 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -95,7 +95,7 @@ static int arg_crash_chvt = -1;
static bool arg_crash_shell = false;
static bool arg_crash_reboot = false;
static char *arg_confirm_spawn = NULL;
-static ShowStatus arg_show_status = _SHOW_STATUS_UNSET;
+static ShowStatus arg_show_status = _SHOW_STATUS_INVALID;
static bool arg_switched_root = false;
static bool arg_no_pager = false;
static bool arg_service_watchdogs = true;
@@ -470,7 +470,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
} else if (streq(key, "quiet") && !value) {
- if (arg_show_status == _SHOW_STATUS_UNSET)
+ if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_AUTO;
} else if (streq(key, "debug") && !value) {
@@ -838,19 +838,15 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_LOG_LEVEL:
r = log_set_max_level_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log level %s.", optarg);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse log level \"%s\": %m", optarg);
break;
case ARG_LOG_TARGET:
r = log_set_target_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log target %s.", optarg);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse log target \"%s\": %m", optarg);
break;
@@ -858,10 +854,9 @@ static int parse_argv(int argc, char *argv[]) {
if (optarg) {
r = log_show_color_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log color setting %s.", optarg);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse log color setting \"%s\": %m",
+ optarg);
} else
log_show_color(true);
@@ -870,10 +865,9 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_LOG_LOCATION:
if (optarg) {
r = log_show_location_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log location setting %s.", optarg);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse log location setting \"%s\": %m",
+ optarg);
} else
log_show_location(true);
@@ -881,26 +875,24 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_DEFAULT_STD_OUTPUT:
r = exec_output_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse default standard output setting %s.", optarg);
- return r;
- } else
- arg_default_std_output = r;
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse default standard output setting \"%s\": %m",
+ optarg);
+ arg_default_std_output = r;
break;
case ARG_DEFAULT_STD_ERROR:
r = exec_output_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse default standard error output setting %s.", optarg);
- return r;
- } else
- arg_default_std_error = r;
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse default standard error output setting \"%s\": %m",
+ optarg);
+ arg_default_std_error = r;
break;
case ARG_UNIT:
r = free_and_strdup(&arg_default_unit, optarg);
if (r < 0)
- return log_error_errno(r, "Failed to set default unit %s: %m", optarg);
+ return log_error_errno(r, "Failed to set default unit \"%s\": %m", optarg);
break;
@@ -938,7 +930,8 @@ static int parse_argv(int argc, char *argv[]) {
else {
r = parse_boolean(optarg);
if (r < 0)
- return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg);
+ return log_error_errno(r, "Failed to parse dump core boolean: \"%s\": %m",
+ optarg);
arg_dump_core = r;
}
break;
@@ -946,7 +939,8 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CRASH_CHVT:
r = parse_crash_chvt(optarg);
if (r < 0)
- return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg);
+ return log_error_errno(r, "Failed to parse crash virtual terminal index: \"%s\": %m",
+ optarg);
break;
case ARG_CRASH_SHELL:
@@ -955,7 +949,8 @@ static int parse_argv(int argc, char *argv[]) {
else {
r = parse_boolean(optarg);
if (r < 0)
- return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
+ return log_error_errno(r, "Failed to parse crash shell boolean: \"%s\": %m",
+ optarg);
arg_crash_shell = r;
}
break;
@@ -966,7 +961,8 @@ static int parse_argv(int argc, char *argv[]) {
else {
r = parse_boolean(optarg);
if (r < 0)
- return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
+ return log_error_errno(r, "Failed to parse crash shell boolean: \"%s\": %m",
+ optarg);
arg_crash_reboot = r;
}
break;
@@ -976,23 +972,24 @@ static int parse_argv(int argc, char *argv[]) {
r = parse_confirm_spawn(optarg, &arg_confirm_spawn);
if (r < 0)
- return log_error_errno(r, "Failed to parse confirm spawn option: %m");
+ return log_error_errno(r, "Failed to parse confirm spawn option: \"%s\": %m",
+ optarg);
break;
case ARG_SERVICE_WATCHDOGS:
r = parse_boolean(optarg);
if (r < 0)
- return log_error_errno(r, "Failed to parse service watchdogs boolean: %s", optarg);
+ return log_error_errno(r, "Failed to parse service watchdogs boolean: \"%s\": %m",
+ optarg);
arg_service_watchdogs = r;
break;
case ARG_SHOW_STATUS:
if (optarg) {
r = parse_show_status(optarg, &arg_show_status);
- if (r < 0) {
- log_error("Failed to parse show status boolean %s.", optarg);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse show status boolean: \"%s\": %m",
+ optarg);
} else
arg_show_status = SHOW_STATUS_YES;
break;
@@ -1002,8 +999,10 @@ static int parse_argv(int argc, char *argv[]) {
FILE *f;
r = safe_atoi(optarg, &fd);
- if (r < 0 || fd < 0) {
- log_error("Failed to parse deserialize option %s.", optarg);
+ if (r < 0)
+ log_error_errno(r, "Failed to parse deserialize option \"%s\": %m", optarg);
+ if (fd < 0) {
+ log_error("Invalid deserialize fd: %d", fd);
return -EINVAL;
}
@@ -1011,7 +1010,7 @@ static int parse_argv(int argc, char *argv[]) {
f = fdopen(fd, "r");
if (!f)
- return log_error_errno(errno, "Failed to open serialization fd: %m");
+ return log_error_errno(errno, "Failed to open serialization fd %d: %m", fd);
safe_fclose(arg_serialization);
arg_serialization = f;
@@ -1026,7 +1025,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_MACHINE_ID:
r = set_machine_id(optarg);
if (r < 0)
- return log_error_errno(r, "MachineID '%s' is not valid.", optarg);
+ return log_error_errno(r, "MachineID '%s' is not valid: %m", optarg);
break;
case 'h':
@@ -1219,7 +1218,7 @@ static int status_welcome(void) {
_cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
int r;
- if (arg_show_status <= 0)
+ if (IN_SET(arg_show_status, SHOW_STATUS_NO, SHOW_STATUS_AUTO))
return 0;
r = parse_os_release(NULL,
@@ -1985,7 +1984,7 @@ static int load_configuration(int argc, char **argv, const char **ret_error_mess
}
/* Initialize the show status setting if it hasn't been set explicitly yet */
- if (arg_show_status == _SHOW_STATUS_UNSET)
+ if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_YES;
return 0;
@@ -2373,8 +2372,8 @@ int main(int argc, char *argv[]) {
m->timestamps[MANAGER_TIMESTAMP_KERNEL] = kernel_timestamp;
m->timestamps[MANAGER_TIMESTAMP_INITRD] = initrd_timestamp;
m->timestamps[MANAGER_TIMESTAMP_USERSPACE] = userspace_timestamp;
- m->timestamps[MANAGER_TIMESTAMP_SECURITY_START] = security_start_timestamp;
- m->timestamps[MANAGER_TIMESTAMP_SECURITY_FINISH] = security_finish_timestamp;
+ m->timestamps[manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_SECURITY_START)] = security_start_timestamp;
+ m->timestamps[manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_SECURITY_FINISH)] = security_finish_timestamp;
set_manager_defaults(m);
set_manager_settings(m);
diff --git a/src/core/manager.c b/src/core/manager.c
index ada8712fd5..8dc3f5e55f 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1555,9 +1555,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_GENERATORS_START);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START));
r = manager_run_generators(m);
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_GENERATORS_FINISH);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_FINISH));
if (r < 0)
return r;
@@ -1572,10 +1572,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->n_reloading++;
/* First, enumerate what we can from all config files */
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_START);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_UNITS_LOAD_START));
manager_enumerate_perpetual(m);
manager_enumerate(m);
- dual_timestamp_get(m->timestamps + MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
+ dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_UNITS_LOAD_FINISH));
/* Second, deserialize if there is something to deserialize */
if (serialization) {
@@ -3016,14 +3016,22 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "taint-logged=%s\n", yes_no(m->taint_logged));
fprintf(f, "service-watchdogs=%s\n", yes_no(m->service_watchdogs));
+ t = show_status_to_string(m->show_status);
+ if (t)
+ fprintf(f, "show-status=%s\n", t);
+
if (m->log_level_overridden)
fprintf(f, "log-level-override=%i\n", log_get_max_level());
if (m->log_target_overridden)
fprintf(f, "log-target-override=%s\n", log_target_to_string(log_get_target()));
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
- /* The userspace and finish timestamps only apply to the host system, hence only serialize them there */
- if (in_initrd() && IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH))
+ /* The following timestamps only apply to the host system, hence only serialize them there */
+ if (in_initrd() &&
+ IN_SET(q, MANAGER_TIMESTAMP_USERSPACE, MANAGER_TIMESTAMP_FINISH,
+ MANAGER_TIMESTAMP_SECURITY_START, MANAGER_TIMESTAMP_SECURITY_FINISH,
+ MANAGER_TIMESTAMP_GENERATORS_START, MANAGER_TIMESTAMP_GENERATORS_FINISH,
+ MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH))
continue;
t = manager_timestamp_to_string(q);
@@ -3205,6 +3213,15 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
else
m->service_watchdogs = b;
+ } else if ((val = startswith(l, "show-status="))) {
+ ShowStatus s;
+
+ s = show_status_from_string(val);
+ if (s < 0)
+ log_notice("Failed to parse show-status flag %s", val);
+ else
+ manager_set_show_status(m, s);
+
} else if ((val = startswith(l, "log-level-override="))) {
int level;
@@ -3912,7 +3929,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
mode == SHOW_STATUS_NO ? "Disabling" : "Enabling");
m->show_status = mode;
- if (mode > 0)
+ if (IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES))
(void) touch("/run/systemd/show-status");
else
(void) unlink("/run/systemd/show-status");
@@ -3934,7 +3951,7 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
return false;
- return m->show_status > 0;
+ return IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
}
const char *manager_get_confirm_spawn(Manager *m) {
@@ -4514,6 +4531,14 @@ void manager_restore_original_log_target(Manager *m) {
m->log_target_overridden = false;
}
+ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s) {
+ if (in_initrd() &&
+ s >= MANAGER_TIMESTAMP_SECURITY_START &&
+ s <= MANAGER_TIMESTAMP_UNITS_LOAD_FINISH)
+ return s - MANAGER_TIMESTAMP_SECURITY_START + MANAGER_TIMESTAMP_INITRD_SECURITY_START;
+ return s;
+}
+
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
@@ -4538,6 +4563,12 @@ static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
[MANAGER_TIMESTAMP_GENERATORS_FINISH] = "generators-finish",
[MANAGER_TIMESTAMP_UNITS_LOAD_START] = "units-load-start",
[MANAGER_TIMESTAMP_UNITS_LOAD_FINISH] = "units-load-finish",
+ [MANAGER_TIMESTAMP_INITRD_SECURITY_START] = "initrd-security-start",
+ [MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH] = "initrd-security-finish",
+ [MANAGER_TIMESTAMP_INITRD_GENERATORS_START] = "initrd-generators-start",
+ [MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH] = "initrd-generators-finish",
+ [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START] = "initrd-units-load-start",
+ [MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH] = "initrd-units-load-finish",
};
DEFINE_STRING_TABLE_LOOKUP(manager_timestamp, ManagerTimestamp);
diff --git a/src/core/manager.h b/src/core/manager.h
index ea5d425030..342258fcf9 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -67,6 +67,13 @@ typedef enum ManagerTimestamp {
MANAGER_TIMESTAMP_GENERATORS_FINISH,
MANAGER_TIMESTAMP_UNITS_LOAD_START,
MANAGER_TIMESTAMP_UNITS_LOAD_FINISH,
+
+ MANAGER_TIMESTAMP_INITRD_SECURITY_START,
+ MANAGER_TIMESTAMP_INITRD_SECURITY_FINISH,
+ MANAGER_TIMESTAMP_INITRD_GENERATORS_START,
+ MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH,
+ MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START,
+ MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH,
_MANAGER_TIMESTAMP_MAX,
_MANAGER_TIMESTAMP_INVALID = -1,
} ManagerTimestamp;
@@ -479,3 +486,4 @@ void manager_disable_confirm_spawn(void);
const char *manager_timestamp_to_string(ManagerTimestamp m) _const_;
ManagerTimestamp manager_timestamp_from_string(const char *s) _pure_;
+ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);
diff --git a/src/core/mount.c b/src/core/mount.c
index 21437dad08..16229d4af1 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -747,10 +747,11 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
ExecParameters exec_params = {
- .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
+ .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
+ .exec_fd = -1,
};
pid_t pid;
int r;
diff --git a/src/core/service.c b/src/core/service.c
index db1356c417..6abf87cb39 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -79,9 +79,10 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
[SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
};
-static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata);
+static int service_dispatch_inotify_io(sd_event_source *source, int fd, uint32_t events, void *userdata);
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata);
+static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata);
static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
static void service_enter_reload_by_notify(Service *s);
@@ -389,6 +390,7 @@ static void service_done(Unit *u) {
service_stop_watchdog(s);
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
+ s->exec_fd_event_source = sd_event_source_unref(s->exec_fd_event_source);
service_release_resources(u);
}
@@ -1066,6 +1068,9 @@ static void service_set_state(Service *s, ServiceState state) {
!(state == SERVICE_DEAD && UNIT(s)->job))
service_close_socket_fd(s);
+ if (state != SERVICE_START)
+ s->exec_fd_event_source = sd_event_source_unref(s->exec_fd_event_source);
+
if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
service_stop_watchdog(s);
@@ -1178,21 +1183,23 @@ static int service_coldplug(Unit *u) {
return 0;
}
-static int service_collect_fds(Service *s,
- int **fds,
- char ***fd_names,
- unsigned *n_storage_fds,
- unsigned *n_socket_fds) {
+static int service_collect_fds(
+ Service *s,
+ int **fds,
+ char ***fd_names,
+ size_t *n_socket_fds,
+ size_t *n_storage_fds) {
_cleanup_strv_free_ char **rfd_names = NULL;
_cleanup_free_ int *rfds = NULL;
- unsigned rn_socket_fds = 0, rn_storage_fds = 0;
+ size_t rn_socket_fds = 0, rn_storage_fds = 0;
int r;
assert(s);
assert(fds);
assert(fd_names);
assert(n_socket_fds);
+ assert(n_storage_fds);
if (s->socket_fd >= 0) {
@@ -1256,7 +1263,7 @@ static int service_collect_fds(Service *s,
if (s->n_fd_store > 0) {
ServiceFDStore *fs;
- unsigned n_fds;
+ size_t n_fds;
char **nl;
int *t;
@@ -1294,6 +1301,63 @@ static int service_collect_fds(Service *s,
return 0;
}
+static int service_allocate_exec_fd_event_source(
+ Service *s,
+ int fd,
+ sd_event_source **ret_event_source) {
+
+ _cleanup_(sd_event_source_unrefp) sd_event_source *source = NULL;
+ int r;
+
+ assert(s);
+ assert(fd >= 0);
+ assert(ret_event_source);
+
+ r = sd_event_add_io(UNIT(s)->manager->event, &source, fd, 0, service_dispatch_exec_io, s);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to allocate exec_fd event source: %m");
+
+ /* This is a bit lower priority than SIGCHLD, as that carries a lot more interesting failure information */
+
+ r = sd_event_source_set_priority(source, SD_EVENT_PRIORITY_NORMAL-3);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to adjust priority of exec_fd event source: %m");
+
+ (void) sd_event_source_set_description(source, "service event_fd");
+
+ r = sd_event_source_set_io_fd_own(source, true);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to pass ownership of fd to event source: %m");
+
+ *ret_event_source = TAKE_PTR(source);
+ return 0;
+}
+
+static int service_allocate_exec_fd(
+ Service *s,
+ sd_event_source **ret_event_source,
+ int* ret_exec_fd) {
+
+ _cleanup_close_pair_ int p[2] = { -1, -1 };
+ int r;
+
+ assert(s);
+ assert(ret_event_source);
+ assert(ret_exec_fd);
+
+ if (pipe2(p, O_CLOEXEC|O_NONBLOCK) < 0)
+ return log_unit_error_errno(UNIT(s), errno, "Failed to allocate exec_fd pipe: %m");
+
+ r = service_allocate_exec_fd_event_source(s, p[0], ret_event_source);
+ if (r < 0)
+ return r;
+
+ p[0] = -1;
+ *ret_exec_fd = TAKE_FD(p[1]);
+
+ return 0;
+}
+
static bool service_exec_needs_notify_socket(Service *s, ExecFlags flags) {
assert(s);
@@ -1325,9 +1389,12 @@ static int service_spawn(
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
+ .exec_fd = -1,
};
_cleanup_strv_free_ char **final_env = NULL, **our_env = NULL, **fd_names = NULL;
- unsigned n_storage_fds = 0, n_socket_fds = 0, n_env = 0;
+ _cleanup_(sd_event_source_unrefp) sd_event_source *exec_fd_source = NULL;
+ size_t n_socket_fds = 0, n_storage_fds = 0, n_env = 0;
+ _cleanup_close_ int exec_fd = -1;
_cleanup_free_ int *fds = NULL;
pid_t pid;
int r;
@@ -1353,11 +1420,19 @@ static int service_spawn(
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
- r = service_collect_fds(s, &fds, &fd_names, &n_storage_fds, &n_socket_fds);
+ r = service_collect_fds(s, &fds, &fd_names, &n_socket_fds, &n_storage_fds);
if (r < 0)
return r;
- log_unit_debug(UNIT(s), "Passing %i fds to service", n_storage_fds + n_socket_fds);
+ log_unit_debug(UNIT(s), "Passing %zu fds to service", n_socket_fds + n_storage_fds);
+ }
+
+ if (!FLAGS_SET(flags, EXEC_IS_CONTROL) && s->type == SERVICE_EXEC) {
+ assert(!s->exec_fd_event_source);
+
+ r = service_allocate_exec_fd(s, &exec_fd_source, &exec_fd);
+ if (r < 0)
+ return r;
}
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
@@ -1450,8 +1525,8 @@ static int service_spawn(
exec_params.environment = final_env;
exec_params.fds = fds;
exec_params.fd_names = fd_names;
- exec_params.n_storage_fds = n_storage_fds;
exec_params.n_socket_fds = n_socket_fds;
+ exec_params.n_storage_fds = n_storage_fds;
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
if (s->type == SERVICE_IDLE)
@@ -1459,6 +1534,7 @@ static int service_spawn(
exec_params.stdin_fd = s->stdin_fd;
exec_params.stdout_fd = s->stdout_fd;
exec_params.stderr_fd = s->stderr_fd;
+ exec_params.exec_fd = exec_fd;
r = exec_spawn(UNIT(s),
c,
@@ -1470,6 +1546,9 @@ static int service_spawn(
if (r < 0)
return r;
+ s->exec_fd_event_source = TAKE_PTR(exec_fd_source);
+ s->exec_fd_hot = false;
+
r = unit_watch_pid(UNIT(s), pid);
if (r < 0) /* FIXME: we need to do something here */
return r;
@@ -1981,14 +2060,12 @@ static void service_enter_start(Service *s) {
s->control_pid = pid;
service_set_state(s, SERVICE_START);
- } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY)) {
+ } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_EXEC)) {
- /* For oneshot services we wait until the start
- * process exited, too, but it is our main process. */
+ /* For oneshot services we wait until the start process exited, too, but it is our main process. */
- /* For D-Bus services we know the main pid right away,
- * but wait for the bus name to appear on the
- * bus. Notify services are similar. */
+ /* For D-Bus services we know the main pid right away, but wait for the bus name to appear on the
+ * bus. 'notify' and 'exec' services are similar. */
service_set_main_pid(s, pid);
service_set_state(s, SERVICE_START);
@@ -2441,6 +2518,13 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (r < 0)
return r;
+ if (s->exec_fd_event_source) {
+ r = unit_serialize_item_fd(u, f, fds, "exec-fd", sd_event_source_get_io_fd(s->exec_fd_event_source));
+ if (r < 0)
+ return r;
+ unit_serialize_item(u, f, "exec-fd-hot", yes_no(s->exec_fd_hot));
+ }
+
if (UNIT_ISSET(s->accept_socket)) {
r = unit_serialize_item(u, f, "accept-socket", UNIT_DEREF(s->accept_socket)->id);
if (r < 0)
@@ -2774,6 +2858,18 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->stderr_fd = fdset_remove(fds, fd);
s->exec_context.stdio_as_fds = true;
}
+ } else if (streq(key, "exec-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse exec-fd value: %s", value);
+ else {
+ s->exec_fd_event_source = sd_event_source_unref(s->exec_fd_event_source);
+
+ fd = fdset_remove(fds, fd);
+ if (service_allocate_exec_fd_event_source(s, fd, &s->exec_fd_event_source) < 0)
+ safe_close(fd);
+ }
} else if (streq(key, "watchdog-override-usec")) {
usec_t watchdog_override_usec;
if (timestamp_deserialize(value, &watchdog_override_usec) < 0)
@@ -2857,7 +2953,7 @@ static int service_watch_pid_file(Service *s) {
log_unit_debug(UNIT(s), "Setting watch for PID file %s", s->pid_file_pathspec->path);
- r = path_spec_watch(s->pid_file_pathspec, service_dispatch_io);
+ r = path_spec_watch(s->pid_file_pathspec, service_dispatch_inotify_io);
if (r < 0)
goto fail;
@@ -2901,7 +2997,7 @@ static int service_demand_pid_file(Service *s) {
return service_watch_pid_file(s);
}
-static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
+static int service_dispatch_inotify_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
PathSpec *p = userdata;
Service *s;
@@ -2934,6 +3030,59 @@ fail:
return 0;
}
+static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
+ Service *s = SERVICE(userdata);
+
+ assert(s);
+
+ log_unit_debug(UNIT(s), "got exec-fd event");
+
+ /* If Type=exec is set, we'll consider a service started successfully the instant we invoked execve()
+ * successfully for it. We implement this through a pipe() towards the child, which the kernel automatically
+ * closes for us due to O_CLOEXEC on execve() in the child, which then triggers EOF on the pipe in the
+ * parent. We need to be careful however, as there are other reasons that we might cause the child's side of
+ * the pipe to be closed (for example, a simple exit()). To deal with that we'll ignore EOFs on the pipe unless
+ * the child signalled us first that it is about to call the execve(). It does so by sending us a simple
+ * non-zero byte via the pipe. We also provide the child with a way to inform us in case execve() failed: if it
+ * sends a zero byte we'll ignore POLLHUP on the fd again. */
+
+ for (;;) {
+ uint8_t x;
+ ssize_t n;
+
+ n = read(fd, &x, sizeof(x));
+ if (n < 0) {
+ if (errno == EAGAIN) /* O_NONBLOCK in effect → everything queued has now been processed. */
+ return 0;
+
+ return log_unit_error_errno(UNIT(s), errno, "Failed to read from exec_fd: %m");
+ }
+ if (n == 0) { /* EOF → the event we are waiting for */
+
+ s->exec_fd_event_source = sd_event_source_unref(s->exec_fd_event_source);
+
+ if (s->exec_fd_hot) { /* Did the child tell us to expect EOF now? */
+ log_unit_debug(UNIT(s), "Got EOF on exec-fd");
+
+ s->exec_fd_hot = false;
+
+ /* Nice! This is what we have been waiting for. Transition to next state. */
+ if (s->type == SERVICE_EXEC && s->state == SERVICE_START)
+ service_enter_start_post(s);
+ } else
+ log_unit_debug(UNIT(s), "Got EOF on exec-fd while it was disabled, ignoring.");
+
+ return 0;
+ }
+
+ /* A byte was read → this turns on/off the exec fd logic */
+ assert(n == sizeof(x));
+ s->exec_fd_hot = x;
+ }
+
+ return 0;
+}
+
static void service_notify_cgroup_empty_event(Unit *u) {
Service *s = SERVICE(u);
@@ -3843,7 +3992,8 @@ static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
[SERVICE_ONESHOT] = "oneshot",
[SERVICE_DBUS] = "dbus",
[SERVICE_NOTIFY] = "notify",
- [SERVICE_IDLE] = "idle"
+ [SERVICE_IDLE] = "idle",
+ [SERVICE_EXEC] = "exec",
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
diff --git a/src/core/service.h b/src/core/service.h
index 9c06e91883..b53e4204e7 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -30,6 +30,7 @@ typedef enum ServiceType {
SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
+ SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */
_SERVICE_TYPE_MAX,
_SERVICE_TYPE_INVALID = -1
} ServiceType;
@@ -165,6 +166,8 @@ struct Service {
NotifyAccess notify_access;
NotifyState notify_state;
+ sd_event_source *exec_fd_event_source;
+
ServiceFDStore *fd_store;
size_t n_fd_store;
unsigned n_fd_store_max;
@@ -179,6 +182,7 @@ struct Service {
unsigned n_restarts;
bool flush_n_restarts;
+ bool exec_fd_hot;
};
extern const UnitVTable service_vtable;
diff --git a/src/core/show-status.c b/src/core/show-status.c
index fd9aeb9416..d8d2317d38 100644
--- a/src/core/show-status.c
+++ b/src/core/show-status.c
@@ -5,26 +5,30 @@
#include "io-util.h"
#include "parse-util.h"
#include "show-status.h"
+#include "string-table.h"
#include "string-util.h"
#include "terminal-util.h"
#include "util.h"
+static const char* const show_status_table[_SHOW_STATUS_MAX] = {
+ [SHOW_STATUS_NO] = "no",
+ [SHOW_STATUS_AUTO] = "auto",
+ [SHOW_STATUS_TEMPORARY] = "temporary",
+ [SHOW_STATUS_YES] = "yes",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(show_status, ShowStatus, SHOW_STATUS_YES);
+
int parse_show_status(const char *v, ShowStatus *ret) {
- int r;
+ ShowStatus s;
- assert(v);
assert(ret);
- if (streq(v, "auto")) {
- *ret = SHOW_STATUS_AUTO;
- return 0;
- }
-
- r = parse_boolean(v);
- if (r < 0)
- return r;
+ s = show_status_from_string(v);
+ if (s < 0 || s == SHOW_STATUS_TEMPORARY)
+ return -EINVAL;
- *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO;
+ *ret = s;
return 0;
}
diff --git a/src/core/show-status.h b/src/core/show-status.h
index 1a80de33d9..ac590303c1 100644
--- a/src/core/show-status.h
+++ b/src/core/show-status.h
@@ -8,13 +8,16 @@
/* Manager status */
typedef enum ShowStatus {
- _SHOW_STATUS_UNSET = -2,
- SHOW_STATUS_AUTO = -1,
- SHOW_STATUS_NO = 0,
- SHOW_STATUS_YES = 1,
- SHOW_STATUS_TEMPORARY = 2,
+ SHOW_STATUS_NO,
+ SHOW_STATUS_AUTO,
+ SHOW_STATUS_TEMPORARY,
+ SHOW_STATUS_YES,
+ _SHOW_STATUS_MAX,
+ _SHOW_STATUS_INVALID = -1,
} ShowStatus;
+ShowStatus show_status_from_string(const char *v) _const_;
+const char* show_status_to_string(ShowStatus s) _pure_;
int parse_show_status(const char *v, ShowStatus *ret);
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
diff --git a/src/core/socket.c b/src/core/socket.c
index 56d32225c4..d488c64e91 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1867,10 +1867,11 @@ static int socket_coldplug(Unit *u) {
static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
ExecParameters exec_params = {
- .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
+ .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
+ .exec_fd = -1,
};
pid_t pid;
int r;
diff --git a/src/core/swap.c b/src/core/swap.c
index b78b1aa266..e01e61e56d 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -606,6 +606,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
+ .exec_fd = -1,
};
pid_t pid;
int r;
diff --git a/src/core/unit.c b/src/core/unit.c
index 113205bf25..23433be31c 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -4479,7 +4479,7 @@ static int operation_to_signal(KillContext *c, KillOperation k) {
return c->kill_signal;
case KILL_KILL:
- return SIGKILL;
+ return c->final_kill_signal;
case KILL_ABORT:
return SIGABRT;
diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c
index 99d07c14fb..e7ba8d3664 100644
--- a/src/coredump/coredumpctl.c
+++ b/src/coredump/coredumpctl.c
@@ -654,7 +654,8 @@ static int dump_list(int argc, char **argv, void *userdata) {
* pick a fairly low data threshold here */
sd_journal_set_data_threshold(j, 4096);
- if (arg_one) {
+ /* "info" without pattern implies "-1" */
+ if (arg_one || (verb_is_info && argc == 1)) {
r = focus(j);
if (r < 0)
return r;
diff --git a/src/escape/escape.c b/src/escape/escape.c
index eaf0a9a7af..cd99ca62f4 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- Copyright © 2014 Michael Biebl
-***/
#include <getopt.h>
#include <stdio.h>
diff --git a/src/import/export-raw.c b/src/import/export-raw.c
index f97ae461c5..f3a34d40c5 100644
--- a/src/import/export-raw.c
+++ b/src/import/export-raw.c
@@ -16,6 +16,7 @@
#include "export-raw.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "import-common.h"
#include "missing.h"
#include "ratelimit.h"
@@ -244,13 +245,9 @@ static int raw_export_on_defer(sd_event_source *s, void *userdata) {
}
static int reflink_snapshot(int fd, const char *path) {
- char *p, *d;
int new_fd, r;
- p = strdupa(path);
- d = dirname(p);
-
- new_fd = open(d, O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0600);
+ new_fd = open_parent(path, O_TMPFILE|O_CLOEXEC|O_RDWR, 0600);
if (new_fd < 0) {
_cleanup_free_ char *t = NULL;
diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h
index bf78c3e9c3..fc95b3be7c 100644
--- a/src/journal/fsprg.h
+++ b/src/journal/fsprg.h
@@ -22,7 +22,6 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
- *
*/
#include <inttypes.h>
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 43f70c861a..e48260206f 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -10,7 +10,6 @@
* If you change this file you probably should also change its documentation:
*
* http://www.freedesktop.org/wiki/Software/systemd/journal-files
- *
*/
typedef struct Header Header;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index a87f4625ec..4412fe152f 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -949,7 +949,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
return -EINVAL;
if (machine) {
- if (!machine_name_is_valid(machine))
+ if (!streq(machine, ".host") && !machine_name_is_valid(machine))
return -EINVAL;
free_and_replace(b->machine, machine);
@@ -1447,7 +1447,7 @@ _public_ int sd_bus_open_system_machine(sd_bus **ret, const char *machine) {
assert_return(machine, -EINVAL);
assert_return(ret, -EINVAL);
- assert_return(machine_name_is_valid(machine), -EINVAL);
+ assert_return(streq(machine, ".host") || machine_name_is_valid(machine), -EINVAL);
r = sd_bus_new(&b);
if (r < 0)
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h
index f60d54af1b..996008bf6d 100644
--- a/src/libsystemd/sd-device/device-internal.h
+++ b/src/libsystemd/sd-device/device-internal.h
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "sd-device.h"
+
#include "hashmap.h"
#include "set.h"
diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c
index 5c612d9a2f..6017784074 100644
--- a/src/libsystemd/sd-hwdb/sd-hwdb.c
+++ b/src/libsystemd/sd-hwdb/sd-hwdb.c
@@ -148,7 +148,6 @@ static int hwdb_add_property(sd_hwdb *hwdb, const struct trie_value_entry_f *ent
if (old) {
/* On duplicates, we order by filename priority and line-number.
*
- *
* v2 of the format had 64 bits for the line number.
* v3 reuses top 32 bits of line_number to store the priority.
* We check the top bits — if they are zero we have v2 format.
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 9dfba51cea..5940eccead 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -890,20 +890,27 @@ _public_ int sd_machine_get_class(const char *machine, char **class) {
const char *p;
int r;
- assert_return(machine_name_is_valid(machine), -EINVAL);
assert_return(class, -EINVAL);
- p = strjoina("/run/systemd/machines/", machine);
- r = parse_env_file(NULL, p, NEWLINE, "CLASS", &c, NULL);
- if (r == -ENOENT)
- return -ENXIO;
- if (r < 0)
- return r;
- if (!c)
- return -EIO;
+ if (streq(machine, ".host")) {
+ c = strdup("host");
+ if (!c)
+ return -ENOMEM;
+ } else {
+ if (!machine_name_is_valid(machine))
+ return -EINVAL;
- *class = TAKE_PTR(c);
+ p = strjoina("/run/systemd/machines/", machine);
+ r = parse_env_file(NULL, p, NEWLINE, "CLASS", &c, NULL);
+ if (r == -ENOENT)
+ return -ENXIO;
+ if (r < 0)
+ return r;
+ if (!c)
+ return -EIO;
+ }
+ *class = TAKE_PTR(c);
return 0;
}
diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules.m4
index 3515d292ac..d55e5bf5ce 100644
--- a/src/login/70-uaccess.rules
+++ b/src/login/70-uaccess.rules.m4
@@ -46,6 +46,10 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess"
# DRI video devices
SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess"
+m4_ifdef(`DEV_KVM_UACCESS',``
+# KVM
+SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"''
+)m4_dnl
# smart-card readers
ENV{ID_SMARTCARD_READER}=="?*", TAG+="uaccess"
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index e18a6f0efe..346f792fb8 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -711,9 +711,9 @@ int config_parse_tmpfs_size(
assert(data);
/* First, try to parse as percentage */
- r = parse_percent(rvalue);
- if (r > 0 && r < 100)
- *sz = physical_memory_scale(r, 100U);
+ r = parse_permille(rvalue);
+ if (r > 0 && r < 1000)
+ *sz = physical_memory_scale(r, 1000U);
else {
uint64_t k;
diff --git a/src/login/meson.build b/src/login/meson.build
index 4326a452c6..0e1ed18f7a 100644
--- a/src/login/meson.build
+++ b/src/login/meson.build
@@ -81,10 +81,6 @@ if conf.get('ENABLE_LOGIND') == 1
install_data('70-power-switch.rules', install_dir : udevrulesdir)
- if conf.get('HAVE_ACL') == 1
- install_data('70-uaccess.rules', install_dir : udevrulesdir)
- endif
-
seat_rules = configure_file(
input : '71-seat.rules.in',
output : '71-seat.rules',
@@ -93,6 +89,15 @@ if conf.get('ENABLE_LOGIND') == 1
install_dir : udevrulesdir)
custom_target(
+ '70-uaccess.rules',
+ input : '70-uaccess.rules.m4',
+ output: '70-uaccess.rules',
+ command : [meson_apply_m4, config_h, '@INPUT@'],
+ capture : true,
+ install : conf.get('HAVE_ACL') == 1,
+ install_dir : udevrulesdir)
+
+ custom_target(
'73-seat-late.rules',
input : '73-seat-late.rules.m4',
output: '73-seat-late.rules',
diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy
index f1d1f956d3..78bee24b05 100644
--- a/src/login/org.freedesktop.login1.policy
+++ b/src/login/org.freedesktop.login1.policy
@@ -343,7 +343,7 @@
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
+ <allow_active>yes</allow_active>
</defaults>
</action>
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 1fbf6ba585..9d42d1a3bd 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -16,6 +16,7 @@
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "cgroup-util.h"
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
@@ -24,19 +25,19 @@
#include "login-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "socket-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
-#include "path-util.h"
-#include "cgroup-util.h"
static int parse_argv(
pam_handle_t *handle,
int argc, const char **argv,
const char **class,
const char **type,
+ const char **desktop,
bool *debug) {
unsigned i;
@@ -53,6 +54,10 @@ static int parse_argv(
if (type)
*type = argv[i] + 5;
+ } else if (startswith(argv[i], "desktop=")) {
+ if (desktop)
+ *desktop = argv[i] + 8;
+
} else if (streq(argv[i], "debug")) {
if (debug)
*debug = true;
@@ -109,6 +114,31 @@ static int get_user_data(
return PAM_SUCCESS;
}
+static int socket_from_display(const char *display, char **path) {
+ size_t k;
+ char *f, *c;
+
+ assert(display);
+ assert(path);
+
+ if (!display_is_local(display))
+ return -EINVAL;
+
+ k = strspn(display+1, "0123456789");
+
+ f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
+ if (!f)
+ return -ENOMEM;
+
+ c = stpcpy(f, "/tmp/.X11-unix/X");
+ memcpy(c, display+1, k);
+ c[k] = 0;
+
+ *path = f;
+
+ return 0;
+}
+
static int get_seat_from_display(const char *display, const char **seat, uint32_t *vtnr) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
@@ -160,40 +190,6 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
return 0;
}
-static int export_legacy_dbus_address(
- pam_handle_t *handle,
- uid_t uid,
- const char *runtime) {
-
- _cleanup_free_ char *s = NULL;
- int r = PAM_BUF_ERR;
-
- /* FIXME: We *really* should move the access() check into the
- * daemons that spawn dbus-daemon, instead of forcing
- * DBUS_SESSION_BUS_ADDRESS= here. */
-
- s = strjoin(runtime, "/bus");
- if (!s)
- goto error;
-
- if (access(s, F_OK) < 0)
- return PAM_SUCCESS;
-
- s = mfree(s);
- if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0)
- goto error;
-
- r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0);
- if (r != PAM_SUCCESS)
- goto error;
-
- return PAM_SUCCESS;
-
-error:
- pam_syslog(handle, LOG_ERR, "Failed to set bus variable.");
- return r;
-}
-
static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
@@ -208,9 +204,9 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co
return r;
}
} else {
- r = parse_percent(limit);
+ r = parse_permille(limit);
if (r >= 0) {
- r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+ r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
return r;
@@ -231,8 +227,7 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co
return 0;
}
-static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit)
-{
+static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
@@ -257,23 +252,62 @@ static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, con
uint64_t val;
int r;
- if (!isempty(limit)) {
- r = cg_weight_parse(limit, &val);
- if (r >= 0) {
- r = sd_bus_message_append(m, "(sv)", field, "t", val);
- if (r < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
- return r;
- }
- } else if (streq(field, "CPUWeight"))
- pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight: %s, ignoring.", limit);
- else
- pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight: %s, ignoring.", limit);
- }
+ if (isempty(limit))
+ return 0;
+
+ r = cg_weight_parse(limit, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", field, "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else if (streq(field, "CPUWeight"))
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight: %s, ignoring.", limit);
+ else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight: %s, ignoring.", limit);
return 0;
}
+static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) {
+ const char *v;
+
+ assert(handle);
+ assert(key);
+
+ /* Looks for an environment variable, preferrably in the environment block associated with the specified PAM
+ * handle, falling back to the process' block instead. */
+
+ v = pam_getenv(handle, key);
+ if (!isempty(v))
+ return v;
+
+ v = getenv(key);
+ if (!isempty(v))
+ return v;
+
+ return fallback;
+}
+
+static int update_environment(pam_handle_t *handle, const char *key, const char *value) {
+ int r;
+
+ assert(handle);
+ assert(key);
+
+ /* Updates the environment, but only if there's actually a value set. Also, log about errors */
+
+ if (isempty(value))
+ return PAM_SUCCESS;
+
+ r = pam_misc_setenv(handle, key, value, 0);
+ if (r != PAM_SUCCESS)
+ pam_syslog(handle, LOG_ERR, "Failed to set environment variable %s.", key);
+
+ return r;
+}
+
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
@@ -288,7 +322,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
- *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL,
+ *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL, *desktop_pam = NULL,
*memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int session_fd = -1, existing, r;
@@ -307,6 +341,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
argc, argv,
&class_pam,
&type_pam,
+ &desktop_pam,
&debug) < 0)
return PAM_SESSION_ERR;
@@ -338,10 +373,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return r;
}
- r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
- if (r != PAM_SUCCESS)
- return r;
-
return PAM_SUCCESS;
}
@@ -352,55 +383,41 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_get_item(handle, PAM_RUSER, (const void**) &remote_user);
pam_get_item(handle, PAM_RHOST, (const void**) &remote_host);
- seat = pam_getenv(handle, "XDG_SEAT");
- if (isempty(seat))
- seat = getenv("XDG_SEAT");
-
- cvtnr = pam_getenv(handle, "XDG_VTNR");
- if (isempty(cvtnr))
- cvtnr = getenv("XDG_VTNR");
-
- type = pam_getenv(handle, "XDG_SESSION_TYPE");
- if (isempty(type))
- type = getenv("XDG_SESSION_TYPE");
- if (isempty(type))
- type = type_pam;
-
- class = pam_getenv(handle, "XDG_SESSION_CLASS");
- if (isempty(class))
- class = getenv("XDG_SESSION_CLASS");
- if (isempty(class))
- class = class_pam;
-
- desktop = pam_getenv(handle, "XDG_SESSION_DESKTOP");
- if (isempty(desktop))
- desktop = getenv("XDG_SESSION_DESKTOP");
+ seat = getenv_harder(handle, "XDG_SEAT", NULL);
+ cvtnr = getenv_harder(handle, "XDG_VTNR", NULL);
+ type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
+ class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
+ desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
tty = strempty(tty);
if (strchr(tty, ':')) {
- /* A tty with a colon is usually an X11 display,
- * placed there to show up in utmp. We rearrange
- * things and don't pretend that an X display was a
- * tty. */
-
+ /* A tty with a colon is usually an X11 display, placed there to show up in utmp. We rearrange things
+ * and don't pretend that an X display was a tty. */
if (isempty(display))
display = tty;
tty = NULL;
+
} else if (streq(tty, "cron")) {
- /* cron has been setting PAM_TTY to "cron" for a very
- * long time and it probably shouldn't stop doing that
- * for compatibility reasons. */
+ /* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but
+ * probably because it wants to set it to something as pam_time/pam_access/… require PAM_TTY to be set
+ * (as they otherwise even try to update it!) — but cron doesn't actually allocate a TTY for its forked
+ * off processes.) */
type = "unspecified";
class = "background";
tty = NULL;
+
} else if (streq(tty, "ssh")) {
- /* ssh has been setting PAM_TTY to "ssh" for a very
- * long time and probably shouldn't stop doing that
- * for compatibility reasons. */
+ /* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further
+ * details look for "PAM_TTY_KLUDGE" in the openssh sources). */
type ="tty";
class = "user";
- tty = NULL;
+ tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though usually
+ * associated with a pty — won't be tracked by their tty in logind. This is because ssh
+ * does the PAM session registration early for new connections, and registers a pty only
+ * much later (this is because it doesn't know yet if it needs one at all, as whether to
+ * register a pty or not is negotiated much later in the protocol). */
+
} else
/* Chop off leading /dev prefix that some clients specify, but others do not. */
tty = skip_dev_prefix(tty);
@@ -411,9 +428,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (!isempty(display) && !vtnr) {
if (isempty(seat))
- get_seat_from_display(display, &seat, &vtnr);
+ (void) get_seat_from_display(display, &seat, &vtnr);
else if (streq(seat, "seat0"))
- get_seat_from_display(display, NULL, &vtnr);
+ (void) get_seat_from_display(display, NULL, &vtnr);
}
if (seat && !streq(seat, "seat0") && vtnr != 0) {
@@ -546,11 +563,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
"id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u",
id, object_path, runtime_path, session_fd, seat, vtnr, original_uid);
- r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set session id.");
+ r = update_environment(handle, "XDG_SESSION_ID", id);
+ if (r != PAM_SUCCESS)
return r;
- }
if (original_uid == pw->pw_uid) {
/* Don't set $XDG_RUNTIME_DIR if the user we now
@@ -559,34 +574,38 @@ _public_ PAM_EXTERN int pam_sm_open_session(
* in privileged apps clobbering the runtime directory
* unnecessarily. */
- r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
- return r;
- }
-
- r = export_legacy_dbus_address(handle, pw->pw_uid, runtime_path);
+ r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_path);
if (r != PAM_SUCCESS)
return r;
}
- if (!isempty(seat)) {
- r = pam_misc_setenv(handle, "XDG_SEAT", seat, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set seat.");
- return r;
- }
- }
+ /* Most likely we got the session/type/class from environment variables, but might have gotten the data
+ * somewhere else (for example PAM module parameters). Let's now update the environment variables, so that this
+ * data is inherited into the session processes, and programs can rely on them to be initialized. */
+
+ r = update_environment(handle, "XDG_SESSION_TYPE", type);
+ if (r != PAM_SUCCESS)
+ return r;
+
+ r = update_environment(handle, "XDG_SESSION_CLASS", class);
+ if (r != PAM_SUCCESS)
+ return r;
+
+ r = update_environment(handle, "XDG_SESSION_DESKTOP", desktop);
+ if (r != PAM_SUCCESS)
+ return r;
+
+ r = update_environment(handle, "XDG_SEAT", seat);
+ if (r != PAM_SUCCESS)
+ return r;
if (vtnr > 0) {
char buf[DECIMAL_STR_MAX(vtnr)];
sprintf(buf, "%u", vtnr);
- r = pam_misc_setenv(handle, "XDG_VTNR", buf, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set virtual terminal number.");
+ r = update_environment(handle, "XDG_VTNR", buf);
+ if (r != PAM_SUCCESS)
return r;
- }
}
r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL);
@@ -628,7 +647,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
/* Only release session if it wasn't pre-existing when we
* tried to create it */
- pam_get_data(handle, "systemd.existing", &existing);
+ (void) pam_get_data(handle, "systemd.existing", &existing);
id = pam_getenv(handle, "XDG_SESSION_ID");
if (id && !existing) {
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 7f41465ccd..77e8b161b0 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -1058,7 +1058,7 @@ finish:
}
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
+ const char *src, *dest, *host_path, *container_path, *host_basename, *container_basename, *container_dirname;
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE;
_cleanup_close_ int hostfd = -1;
@@ -1119,16 +1119,14 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
}
host_basename = basename(host_path);
- t = strdupa(host_path);
- host_dirname = dirname(t);
container_basename = basename(container_path);
t = strdupa(container_path);
container_dirname = dirname(t);
- hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
+ hostfd = open_parent(host_path, O_CLOEXEC, 0);
if (hostfd < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
+ return sd_bus_error_set_errnof(error, hostfd, "Failed to open host directory %s: %m", host_path);
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
diff --git a/src/network/netdev/vrf.c b/src/network/netdev/vrf.c
index f341061344..b18090f7a1 100644
--- a/src/network/netdev/vrf.c
+++ b/src/network/netdev/vrf.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- Copyright © 2016 Andreas Rammhold <andreas@rammhold.de>
-***/
#include <net/if.h>
diff --git a/src/network/netdev/vrf.h b/src/network/netdev/vrf.h
index d1ac6f6976..05b3937856 100644
--- a/src/network/netdev/vrf.h
+++ b/src/network/netdev/vrf.h
@@ -1,10 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-/***
- Copyright © 2016 Andreas Rammhold <andreas@rammhold.de>
-***/
-
typedef struct Vrf Vrf;
#include "netdev/netdev.h"
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 0fcd2cab3e..fb729406dd 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -119,7 +119,7 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
Link *link;
Manager *manager = dhcp6_link->manager;
union in_addr_union prefix;
- uint8_t n_prefixes, n_used = 0;
+ uint64_t n_prefixes, n_used = 0;
_cleanup_free_ char *buf = NULL;
int r;
@@ -132,17 +132,17 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
if (r < 0)
return r;
- n_prefixes = 1 << (64 - pd_prefix_len);
+ n_prefixes = UINT64_C(1) << (64 - pd_prefix_len);
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
- log_link_debug(dhcp6_link, "Assigning up to %u prefixes from %s/%u",
+ log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s/%u",
n_prefixes, strnull(buf), pd_prefix_len);
while (hashmap_iterate(manager->links, i, (void **)&link, NULL)) {
Link *assigned_link;
if (n_used == n_prefixes) {
- log_link_debug(dhcp6_link, "Assigned %u/%u prefixes from %s/%u",
+ log_link_debug(dhcp6_link, "Assigned %" PRIu64 "/%" PRIu64 " prefixes from %s/%u",
n_used, n_prefixes, strnull(buf), pd_prefix_len);
return -EAGAIN;
@@ -169,7 +169,7 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
continue;
} else
- log_link_debug(link, "Assigned prefix %u/%u %s/64 to link",
+ log_link_debug(link, "Assigned prefix %" PRIu64 "/%" PRIu64 " %s/64 to link",
n_used + 1, n_prefixes, strnull(buf));
n_used++;
@@ -181,7 +181,7 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
if (n_used < n_prefixes) {
Route *route;
- int n = n_used;
+ uint64_t n = n_used;
r = route_new(&route);
if (r < 0)
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index e22c2fe578..3792f3d700 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -1762,7 +1762,7 @@ int manager_set_hostname(Manager *m, const char *hostname) {
return log_oom();
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
- log_info("Not connected to system bus, not setting hostname.");
+ log_debug("Not connected to system bus, setting hostname later.");
return 0;
}
@@ -1810,7 +1810,7 @@ int manager_set_timezone(Manager *m, const char *tz) {
return log_oom();
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
- log_info("Not connected to system bus, not setting timezone.");
+ log_debug("Not connected to system bus, setting timezone later.");
return 0;
}
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index 11cd7faa8b..63a2ba8215 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -22,6 +22,7 @@ int main(int argc, char **argv) {
test_table(bond_primary_reselect, NETDEV_BOND_PRIMARY_RESELECT);
test_table(bond_xmit_hash_policy, NETDEV_BOND_XMIT_HASH_POLICY);
test_table(dhcp6_message_status, DHCP6_STATUS);
+ test_table_sparse(dhcp6_message_type, DHCP6_MESSAGE); /* enum starts from 1 */
test_table(dhcp_use_domains, DHCP_USE_DOMAINS);
test_table(duplex, DUP);
test_table(ip6tnl_mode, NETDEV_IP6_TNL_MODE);
diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c
index d8a39a6959..4a3cd29094 100644
--- a/src/nspawn/nspawn-cgroup.c
+++ b/src/nspawn/nspawn-cgroup.c
@@ -5,12 +5,16 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "mkdir.h"
#include "mount-util.h"
#include "nspawn-cgroup.h"
+#include "nspawn-mount.h"
+#include "path-util.h"
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
+#include "user-util.h"
#include "util.h"
static int chown_cgroup_path(const char *path, uid_t uid_shift) {
@@ -71,7 +75,7 @@ int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
return 0;
}
-int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t arg_uid_shift) {
+int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
_cleanup_free_ char *cgroup = NULL;
char tree[] = "/tmp/unifiedXXXXXX", pid_string[DECIMAL_STR_MAX(pid) + 1];
bool undo_mount = false;
@@ -125,7 +129,7 @@ int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t arg_uid_shift)
}
fn = strjoina(tree, cgroup);
- r = chown_cgroup_path(fn, arg_uid_shift);
+ r = chown_cgroup_path(fn, uid_shift);
if (r < 0)
log_error_errno(r, "Failed to chown() cgroup %s: %m", fn);
finish:
@@ -188,3 +192,416 @@ int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested)
(void) cg_enable_everywhere(supported, supported, cgroup);
return 0;
}
+
+/* Retrieve existing subsystems. This function is called in a new cgroup
+ * namespace.
+ */
+static int get_process_controllers(Set **ret) {
+ _cleanup_set_free_free_ Set *controllers = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ assert(ret);
+
+ controllers = set_new(&string_hash_ops);
+ if (!controllers)
+ return -ENOMEM;
+
+ f = fopen("/proc/self/cgroup", "re");
+ if (!f)
+ return errno == ENOENT ? -ESRCH : -errno;
+
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
+ char *e, *l;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ l = strchr(line, ':');
+ if (!l)
+ continue;
+
+ l++;
+ e = strchr(l, ':');
+ if (!e)
+ continue;
+
+ *e = 0;
+
+ if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
+ continue;
+
+ r = set_put_strdup(controllers, l);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(controllers);
+
+ return 0;
+}
+
+static int mount_legacy_cgroup_hierarchy(
+ const char *dest,
+ const char *controller,
+ const char *hierarchy,
+ bool read_only) {
+
+ const char *to, *fstype, *opts;
+ int r;
+
+ to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
+
+ r = path_is_mount_point(to, dest, 0);
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to);
+ if (r > 0)
+ return 0;
+
+ mkdir_p(to, 0755);
+
+ /* The superblock mount options of the mount point need to be
+ * identical to the hosts', and hence writable... */
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_HYBRID)) {
+ fstype = "cgroup2";
+ opts = NULL;
+ } else if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_LEGACY)) {
+ fstype = "cgroup";
+ opts = "none,name=systemd,xattr";
+ } else {
+ fstype = "cgroup";
+ opts = controller;
+ }
+
+ r = mount_verbose(LOG_ERR, "cgroup", to, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
+ if (r < 0)
+ return r;
+
+ /* ... hence let's only make the bind mount read-only, not the superblock. */
+ if (read_only) {
+ r = mount_verbose(LOG_ERR, NULL, to, NULL,
+ MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
+}
+
+/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
+static int mount_legacy_cgns_supported(
+ const char *dest,
+ CGroupUnified unified_requested,
+ bool userns,
+ uid_t uid_shift,
+ uid_t uid_range,
+ const char *selinux_apifs_context) {
+
+ _cleanup_set_free_free_ Set *controllers = NULL;
+ const char *cgroup_root = "/sys/fs/cgroup", *c;
+ int r;
+
+ (void) mkdir_p(cgroup_root, 0755);
+
+ /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
+ r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
+ if (r == 0) {
+ _cleanup_free_ char *options = NULL;
+
+ /* When cgroup namespaces are enabled and user namespaces are
+ * used then the mount of the cgroupfs is done *inside* the new
+ * user namespace. We're root in the new user namespace and the
+ * kernel will happily translate our uid/gid to the correct
+ * uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
+ * pass uid 0 and not uid_shift to tmpfs_patch_options().
+ */
+ r = tmpfs_patch_options("mode=755", 0, selinux_apifs_context, &options);
+ if (r < 0)
+ return log_oom();
+
+ r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
+ if (r < 0)
+ return r;
+ }
+
+ r = cg_all_unified();
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto skip_controllers;
+
+ r = get_process_controllers(&controllers);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine cgroup controllers: %m");
+
+ for (;;) {
+ _cleanup_free_ const char *controller = NULL;
+
+ controller = set_steal_first(controllers);
+ if (!controller)
+ break;
+
+ r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
+ if (r < 0)
+ return r;
+
+ /* When multiple hierarchies are co-mounted, make their
+ * constituting individual hierarchies a symlink to the
+ * co-mount.
+ */
+ c = controller;
+ for (;;) {
+ _cleanup_free_ char *target = NULL, *tok = NULL;
+
+ r = extract_first_word(&c, &tok, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
+ if (r == 0)
+ break;
+
+ if (streq(controller, tok))
+ break;
+
+ target = prefix_root("/sys/fs/cgroup/", tok);
+ if (!target)
+ return log_oom();
+
+ r = symlink_idempotent(controller, target);
+ if (r == -EINVAL)
+ return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
+ if (r < 0)
+ return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
+ }
+ }
+
+skip_controllers:
+ if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
+ r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
+ if (r < 0)
+ return r;
+ }
+
+ r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
+ if (r < 0)
+ return r;
+
+ if (!userns)
+ return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
+ MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
+
+ return 0;
+}
+
+/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
+static int mount_legacy_cgns_unsupported(
+ const char *dest,
+ CGroupUnified unified_requested,
+ bool userns,
+ uid_t uid_shift,
+ uid_t uid_range,
+ const char *selinux_apifs_context) {
+
+ _cleanup_set_free_free_ Set *controllers = NULL;
+ const char *cgroup_root;
+ int r;
+
+ cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
+
+ (void) mkdir_p(cgroup_root, 0755);
+
+ /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
+ r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
+ if (r == 0) {
+ _cleanup_free_ char *options = NULL;
+
+ r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
+ if (r < 0)
+ return log_oom();
+
+ r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
+ if (r < 0)
+ return r;
+ }
+
+ r = cg_all_unified();
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto skip_controllers;
+
+ r = cg_kernel_controllers(&controllers);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine cgroup controllers: %m");
+
+ for (;;) {
+ _cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;
+
+ controller = set_steal_first(controllers);
+ if (!controller)
+ break;
+
+ origin = prefix_root("/sys/fs/cgroup/", controller);
+ if (!origin)
+ return log_oom();
+
+ r = readlink_malloc(origin, &combined);
+ if (r == -EINVAL) {
+ /* Not a symbolic link, but directly a single cgroup hierarchy */
+
+ r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
+ if (r < 0)
+ return r;
+
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to read link %s: %m", origin);
+ else {
+ _cleanup_free_ char *target = NULL;
+
+ target = prefix_root(dest, origin);
+ if (!target)
+ return log_oom();
+
+ /* A symbolic link, a combination of controllers in one hierarchy */
+
+ if (!filename_is_valid(combined)) {
+ log_warning("Ignoring invalid combined hierarchy %s.", combined);
+ continue;
+ }
+
+ r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
+ if (r < 0)
+ return r;
+
+ r = symlink_idempotent(combined, target);
+ if (r == -EINVAL)
+ return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
+ if (r < 0)
+ return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
+ }
+ }
+
+skip_controllers:
+ if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
+ r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
+ if (r < 0)
+ return r;
+ }
+
+ r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
+ if (r < 0)
+ return r;
+
+ return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
+ MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
+}
+
+static int mount_unified_cgroups(const char *dest) {
+ const char *p;
+ int r;
+
+ assert(dest);
+
+ p = prefix_roota(dest, "/sys/fs/cgroup");
+
+ (void) mkdir_p(p, 0755);
+
+ r = path_is_mount_point(p, dest, AT_SYMLINK_FOLLOW);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
+ if (r > 0) {
+ p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
+ if (access(p, F_OK) >= 0)
+ return 0;
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to determine if mount point %s contains the unified cgroup hierarchy: %m", p);
+
+ log_error("%s is already mounted but not a unified cgroup hierarchy. Refusing.", p);
+ return -EINVAL;
+ }
+
+ return mount_verbose(LOG_ERR, "cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
+}
+
+int mount_cgroups(
+ const char *dest,
+ CGroupUnified unified_requested,
+ bool userns,
+ uid_t uid_shift,
+ uid_t uid_range,
+ const char *selinux_apifs_context,
+ bool use_cgns) {
+
+ if (unified_requested >= CGROUP_UNIFIED_ALL)
+ return mount_unified_cgroups(dest);
+ if (use_cgns)
+ return mount_legacy_cgns_supported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
+
+ return mount_legacy_cgns_unsupported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
+}
+
+static int mount_systemd_cgroup_writable_one(const char *root, const char *own) {
+ int r;
+
+ assert(root);
+ assert(own);
+
+ /* Make our own cgroup a (writable) bind mount */
+ r = mount_verbose(LOG_ERR, own, own, NULL, MS_BIND, NULL);
+ if (r < 0)
+ return r;
+
+ /* And then remount the systemd cgroup root read-only */
+ return mount_verbose(LOG_ERR, NULL, root, NULL,
+ MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
+}
+
+int mount_systemd_cgroup_writable(
+ const char *dest,
+ CGroupUnified unified_requested) {
+
+ _cleanup_free_ char *own_cgroup_path = NULL;
+ const char *root, *own;
+ int r;
+
+ assert(dest);
+
+ r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine our own cgroup path: %m");
+
+ /* If we are living in the top-level, then there's nothing to do... */
+ if (path_equal(own_cgroup_path, "/"))
+ return 0;
+
+ if (unified_requested >= CGROUP_UNIFIED_ALL) {
+
+ root = prefix_roota(dest, "/sys/fs/cgroup");
+ own = strjoina(root, own_cgroup_path);
+
+ } else {
+
+ if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
+ root = prefix_roota(dest, "/sys/fs/cgroup/unified");
+ own = strjoina(root, own_cgroup_path);
+
+ r = mount_systemd_cgroup_writable_one(root, own);
+ if (r < 0)
+ return r;
+ }
+
+ root = prefix_roota(dest, "/sys/fs/cgroup/systemd");
+ own = strjoina(root, own_cgroup_path);
+ }
+
+ return mount_systemd_cgroup_writable_one(root, own);
+}
diff --git a/src/nspawn/nspawn-cgroup.h b/src/nspawn/nspawn-cgroup.h
index 6783c3a39f..035e8fbd0f 100644
--- a/src/nspawn/nspawn-cgroup.h
+++ b/src/nspawn/nspawn-cgroup.h
@@ -9,3 +9,6 @@
int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested);
+
+int mount_cgroups(const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool use_cgns);
+int mount_systemd_cgroup_writable(const char *dest, CGroupUnified unified_requested);
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index b5df65e2a4..1279b9bb3e 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -327,19 +327,15 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
return 0;
}
-static int tmpfs_patch_options(
+int tmpfs_patch_options(
const char *options,
- bool userns,
- uid_t uid_shift, uid_t uid_range,
- bool patch_ids,
+ uid_t uid_shift,
const char *selinux_apifs_context,
char **ret) {
char *buf = NULL;
- if ((userns && uid_shift != 0) || patch_ids) {
- assert(uid_shift != UID_INVALID);
-
+ if (uid_shift != UID_INVALID) {
if (asprintf(&buf, "%s%suid=" UID_FMT ",gid=" UID_FMT,
strempty(options), options ? "," : "",
uid_shift, uid_shift) < 0)
@@ -433,16 +429,14 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
/* Create mountpoint for cgroups. Otherwise we are not allowed since we
* remount /sys read-only.
*/
- if (cg_ns_supported()) {
- x = prefix_roota(top, "/fs/cgroup");
- (void) mkdir_p(x, 0755);
- }
+ x = prefix_roota(top, "/fs/cgroup");
+ (void) mkdir_p(x, 0755);
return mount_verbose(LOG_ERR, NULL, top, NULL,
MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT|extra_flags, NULL);
}
-static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, uid_t uid_shift) {
+static int mkdir_userns(const char *path, mode_t mode, uid_t uid_shift) {
int r;
assert(path);
@@ -451,10 +445,7 @@ static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, u
if (r < 0 && r != -EEXIST)
return r;
- if ((mask & MOUNT_USE_USERNS) == 0)
- return 0;
-
- if (mask & MOUNT_IN_USERNS)
+ if (uid_shift == UID_INVALID)
return 0;
if (lchown(path, uid_shift, uid_shift) < 0)
@@ -463,7 +454,7 @@ static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, u
return 0;
}
-static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, MountSettingsMask mask, uid_t uid_shift) {
+static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, uid_t uid_shift) {
const char *p, *e;
int r;
@@ -490,17 +481,17 @@ static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, Mou
if (prefix && path_startswith(prefix, t))
continue;
- r = mkdir_userns(t, mode, mask, uid_shift);
+ r = mkdir_userns(t, mode, uid_shift);
if (r < 0)
return r;
}
- return mkdir_userns(path, mode, mask, uid_shift);
+ return mkdir_userns(path, mode, uid_shift);
}
int mount_all(const char *dest,
MountSettingsMask mount_settings,
- uid_t uid_shift, uid_t uid_range,
+ uid_t uid_shift,
const char *selinux_apifs_context) {
#define PROC_INACCESSIBLE(path) \
@@ -634,7 +625,7 @@ int mount_all(const char *dest,
if (what && r > 0)
continue;
- r = mkdir_userns_p(dest, where, 0755, mount_settings, uid_shift);
+ r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
if (r < 0 && r != -EEXIST) {
if (fatal && r != -EROFS)
return log_error_errno(r, "Failed to create directory %s: %m", where);
@@ -649,10 +640,7 @@ int mount_all(const char *dest,
o = mount_table[k].options;
if (streq_ptr(mount_table[k].type, "tmpfs")) {
- if (in_userns)
- r = tmpfs_patch_options(o, use_userns, 0, uid_range, true, selinux_apifs_context, &options);
- else
- r = tmpfs_patch_options(o, use_userns, uid_shift, uid_range, false, selinux_apifs_context, &options);
+ r = tmpfs_patch_options(o, in_userns ? 0 : uid_shift, selinux_apifs_context, &options);
if (r < 0)
return log_oom();
if (r > 0)
@@ -755,7 +743,7 @@ static int mount_tmpfs(
return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where);
}
- r = tmpfs_patch_options(m->options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf);
+ r = tmpfs_patch_options(m->options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
return log_oom();
options = r > 0 ? buf : m->options;
@@ -860,419 +848,6 @@ int mount_custom(
return 0;
}
-/* Retrieve existing subsystems. This function is called in a new cgroup
- * namespace.
- */
-static int get_process_controllers(Set **ret) {
- _cleanup_set_free_free_ Set *controllers = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- int r;
-
- assert(ret);
-
- controllers = set_new(&string_hash_ops);
- if (!controllers)
- return -ENOMEM;
-
- f = fopen("/proc/self/cgroup", "re");
- if (!f)
- return errno == ENOENT ? -ESRCH : -errno;
-
- for (;;) {
- _cleanup_free_ char *line = NULL;
- char *e, *l;
-
- r = read_line(f, LONG_LINE_MAX, &line);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- l = strchr(line, ':');
- if (!l)
- continue;
-
- l++;
- e = strchr(l, ':');
- if (!e)
- continue;
-
- *e = 0;
-
- if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
- continue;
-
- r = set_put_strdup(controllers, l);
- if (r < 0)
- return r;
- }
-
- *ret = TAKE_PTR(controllers);
-
- return 0;
-}
-
-static int mount_legacy_cgroup_hierarchy(
- const char *dest,
- const char *controller,
- const char *hierarchy,
- bool read_only) {
-
- const char *to, *fstype, *opts;
- int r;
-
- to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
-
- r = path_is_mount_point(to, dest, 0);
- if (r < 0 && r != -ENOENT)
- return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to);
- if (r > 0)
- return 0;
-
- mkdir_p(to, 0755);
-
- /* The superblock mount options of the mount point need to be
- * identical to the hosts', and hence writable... */
- if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_HYBRID)) {
- fstype = "cgroup2";
- opts = NULL;
- } else if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_LEGACY)) {
- fstype = "cgroup";
- opts = "none,name=systemd,xattr";
- } else {
- fstype = "cgroup";
- opts = controller;
- }
-
- r = mount_verbose(LOG_ERR, "cgroup", to, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
- if (r < 0)
- return r;
-
- /* ... hence let's only make the bind mount read-only, not the superblock. */
- if (read_only) {
- r = mount_verbose(LOG_ERR, NULL, to, NULL,
- MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
- if (r < 0)
- return r;
- }
-
- return 1;
-}
-
-/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
-static int mount_legacy_cgns_supported(
- const char *dest,
- CGroupUnified unified_requested,
- bool userns,
- uid_t uid_shift,
- uid_t uid_range,
- const char *selinux_apifs_context) {
-
- _cleanup_set_free_free_ Set *controllers = NULL;
- const char *cgroup_root = "/sys/fs/cgroup", *c;
- int r;
-
- (void) mkdir_p(cgroup_root, 0755);
-
- /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
- r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
- if (r < 0)
- return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
- if (r == 0) {
- _cleanup_free_ char *options = NULL;
-
- /* When cgroup namespaces are enabled and user namespaces are
- * used then the mount of the cgroupfs is done *inside* the new
- * user namespace. We're root in the new user namespace and the
- * kernel will happily translate our uid/gid to the correct
- * uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
- * pass uid 0 and not uid_shift to tmpfs_patch_options().
- */
- r = tmpfs_patch_options("mode=755", userns, 0, uid_range, true, selinux_apifs_context, &options);
- if (r < 0)
- return log_oom();
-
- r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
- MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
- if (r < 0)
- return r;
- }
-
- r = cg_all_unified();
- if (r < 0)
- return r;
- if (r > 0)
- goto skip_controllers;
-
- r = get_process_controllers(&controllers);
- if (r < 0)
- return log_error_errno(r, "Failed to determine cgroup controllers: %m");
-
- for (;;) {
- _cleanup_free_ const char *controller = NULL;
-
- controller = set_steal_first(controllers);
- if (!controller)
- break;
-
- r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
- if (r < 0)
- return r;
-
- /* When multiple hierarchies are co-mounted, make their
- * constituting individual hierarchies a symlink to the
- * co-mount.
- */
- c = controller;
- for (;;) {
- _cleanup_free_ char *target = NULL, *tok = NULL;
-
- r = extract_first_word(&c, &tok, ",", 0);
- if (r < 0)
- return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
- if (r == 0)
- break;
-
- if (streq(controller, tok))
- break;
-
- target = prefix_root("/sys/fs/cgroup/", tok);
- if (!target)
- return log_oom();
-
- r = symlink_idempotent(controller, target);
- if (r == -EINVAL)
- return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
- if (r < 0)
- return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
- }
- }
-
-skip_controllers:
- if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
- r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
- if (r < 0)
- return r;
- }
-
- r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
- if (r < 0)
- return r;
-
- if (!userns)
- return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
- MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
-
- return 0;
-}
-
-/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
-static int mount_legacy_cgns_unsupported(
- const char *dest,
- CGroupUnified unified_requested,
- bool userns,
- uid_t uid_shift,
- uid_t uid_range,
- const char *selinux_apifs_context) {
-
- _cleanup_set_free_free_ Set *controllers = NULL;
- const char *cgroup_root;
- int r;
-
- cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
-
- (void) mkdir_p(cgroup_root, 0755);
-
- /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
- r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
- if (r < 0)
- return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
- if (r == 0) {
- _cleanup_free_ char *options = NULL;
-
- r = tmpfs_patch_options("mode=755", userns, uid_shift, uid_range, false, selinux_apifs_context, &options);
- if (r < 0)
- return log_oom();
-
- r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
- MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
- if (r < 0)
- return r;
- }
-
- r = cg_all_unified();
- if (r < 0)
- return r;
- if (r > 0)
- goto skip_controllers;
-
- r = cg_kernel_controllers(&controllers);
- if (r < 0)
- return log_error_errno(r, "Failed to determine cgroup controllers: %m");
-
- for (;;) {
- _cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;
-
- controller = set_steal_first(controllers);
- if (!controller)
- break;
-
- origin = prefix_root("/sys/fs/cgroup/", controller);
- if (!origin)
- return log_oom();
-
- r = readlink_malloc(origin, &combined);
- if (r == -EINVAL) {
- /* Not a symbolic link, but directly a single cgroup hierarchy */
-
- r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
- if (r < 0)
- return r;
-
- } else if (r < 0)
- return log_error_errno(r, "Failed to read link %s: %m", origin);
- else {
- _cleanup_free_ char *target = NULL;
-
- target = prefix_root(dest, origin);
- if (!target)
- return log_oom();
-
- /* A symbolic link, a combination of controllers in one hierarchy */
-
- if (!filename_is_valid(combined)) {
- log_warning("Ignoring invalid combined hierarchy %s.", combined);
- continue;
- }
-
- r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
- if (r < 0)
- return r;
-
- r = symlink_idempotent(combined, target);
- if (r == -EINVAL)
- return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
- if (r < 0)
- return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
- }
- }
-
-skip_controllers:
- if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
- r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
- if (r < 0)
- return r;
- }
-
- r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
- if (r < 0)
- return r;
-
- return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
- MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
-}
-
-static int mount_unified_cgroups(const char *dest) {
- const char *p;
- int r;
-
- assert(dest);
-
- p = prefix_roota(dest, "/sys/fs/cgroup");
-
- (void) mkdir_p(p, 0755);
-
- r = path_is_mount_point(p, dest, AT_SYMLINK_FOLLOW);
- if (r < 0)
- return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
- if (r > 0) {
- p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
- if (access(p, F_OK) >= 0)
- return 0;
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to determine if mount point %s contains the unified cgroup hierarchy: %m", p);
-
- log_error("%s is already mounted but not a unified cgroup hierarchy. Refusing.", p);
- return -EINVAL;
- }
-
- return mount_verbose(LOG_ERR, "cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
-}
-
-int mount_cgroups(
- const char *dest,
- CGroupUnified unified_requested,
- bool userns,
- uid_t uid_shift,
- uid_t uid_range,
- const char *selinux_apifs_context,
- bool use_cgns) {
-
- if (unified_requested >= CGROUP_UNIFIED_ALL)
- return mount_unified_cgroups(dest);
- if (use_cgns)
- return mount_legacy_cgns_supported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
-
- return mount_legacy_cgns_unsupported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
-}
-
-static int mount_systemd_cgroup_writable_one(const char *root, const char *own) {
- int r;
-
- assert(root);
- assert(own);
-
- /* Make our own cgroup a (writable) bind mount */
- r = mount_verbose(LOG_ERR, own, own, NULL, MS_BIND, NULL);
- if (r < 0)
- return r;
-
- /* And then remount the systemd cgroup root read-only */
- return mount_verbose(LOG_ERR, NULL, root, NULL,
- MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
-}
-
-int mount_systemd_cgroup_writable(
- const char *dest,
- CGroupUnified unified_requested) {
-
- _cleanup_free_ char *own_cgroup_path = NULL;
- const char *root, *own;
- int r;
-
- assert(dest);
-
- r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
- if (r < 0)
- return log_error_errno(r, "Failed to determine our own cgroup path: %m");
-
- /* If we are living in the top-level, then there's nothing to do... */
- if (path_equal(own_cgroup_path, "/"))
- return 0;
-
- if (unified_requested >= CGROUP_UNIFIED_ALL) {
-
- root = prefix_roota(dest, "/sys/fs/cgroup");
- own = strjoina(root, own_cgroup_path);
-
- } else {
-
- if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
- root = prefix_roota(dest, "/sys/fs/cgroup/unified");
- own = strjoina(root, own_cgroup_path);
-
- r = mount_systemd_cgroup_writable_one(root, own);
- if (r < 0)
- return r;
- }
-
- root = prefix_roota(dest, "/sys/fs/cgroup/systemd");
- own = strjoina(root, own_cgroup_path);
- }
-
- return mount_systemd_cgroup_writable_one(root, own);
-}
-
int setup_volatile_state(
const char *directory,
VolatileMode mode,
@@ -1301,7 +876,7 @@ int setup_volatile_state(
return log_error_errno(errno, "Failed to create %s: %m", directory);
options = "mode=755";
- r = tmpfs_patch_options(options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf);
+ r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
return log_oom();
if (r > 0)
@@ -1334,7 +909,7 @@ int setup_volatile(
return log_error_errno(errno, "Failed to create temporary directory: %m");
options = "mode=755";
- r = tmpfs_patch_options(options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf);
+ r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
return log_oom();
if (r > 0)
diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h
index b823282cbd..db55759ec3 100644
--- a/src/nspawn/nspawn-mount.h
+++ b/src/nspawn/nspawn-mount.h
@@ -43,12 +43,9 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s);
int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
-int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, const char *selinux_apifs_context);
int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
-int mount_cgroups(const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool use_cgns);
-int mount_systemd_cgroup_writable(const char *dest, CGroupUnified unified_requested);
-
int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
@@ -56,3 +53,5 @@ int setup_volatile_state(const char *directory, VolatileMode mode, bool userns,
int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s);
int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old);
+
+int tmpfs_patch_options(const char *options,uid_t uid_shift, const char *selinux_apifs_context, char **ret);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 9ea1c87590..9a2f72bf29 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2558,7 +2558,6 @@ static int inner_child(
r = mount_all(NULL,
arg_mount_settings | MOUNT_IN_USERNS,
arg_uid_shift,
- arg_uid_range,
arg_selinux_apifs_context);
if (r < 0)
return r;
@@ -2990,7 +2989,6 @@ static int outer_child(
r = mount_all(directory,
arg_mount_settings,
arg_uid_shift,
- arg_uid_range,
arg_selinux_apifs_context);
if (r < 0)
return r;
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index f82ce59f2c..5abc0c91bf 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -45,6 +45,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
char *r_name;
unsigned n;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -64,7 +65,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
if (n_addresses <= 0) {
- *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
@@ -81,7 +81,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
/* We respond to our local host name, our hostname suffixed with a single dot. */
if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
- *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
@@ -157,8 +156,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
if (ttlp)
*ttlp = 0;
- /* Explicitly reset all error variables */
- *errnop = 0;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
@@ -286,8 +285,8 @@ static enum nss_status fill_in_hostent(
if (canonp)
*canonp = r_name;
- /* Explicitly reset all error variables */
- *errnop = 0;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
@@ -309,6 +308,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
uint32_t local_address_ipv4 = 0;
int n_addresses = 0;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -334,7 +334,6 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
n_addresses = local_gateways(NULL, 0, af, &addresses);
if (n_addresses <= 0) {
- *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
@@ -350,7 +349,6 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
}
if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
- *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
@@ -393,6 +391,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
bool additional_from_hostname = false;
unsigned n;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(addr);
@@ -455,7 +454,6 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
}
}
- *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index d56d3b4c21..3d1fc28353 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -94,6 +94,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
char *r_name;
int n_ifindices, r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -145,7 +146,6 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
goto fail;
if (c <= 0) {
- *errnop = ESRCH;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
@@ -219,8 +219,8 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
if (ttlp)
*ttlp = 0;
- /* Explicitly reset all error variables */
- *errnop = 0;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
@@ -249,6 +249,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
size_t l, idx, ms, alen;
int r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -302,7 +303,6 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
goto fail;
if (c <= 0) {
- *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
@@ -388,8 +388,8 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
if (canonp)
*canonp = r_name;
- /* Explicitly reset all error variables */
- *errnop = 0;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
@@ -418,6 +418,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
size_t l;
int r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -425,28 +426,28 @@ enum nss_status _nss_mymachines_getpwnam_r(
p = startswith(name, "vu-");
if (!p)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
e = strrchr(p, '-');
if (!e || e == p)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
r = parse_uid(e + 1, &uid);
if (r < 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
machine = strndupa(p, e - p);
if (!machine_name_is_valid(machine))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
/* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
* these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
* running on the host. */
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (avoid_deadlock()) {
r = -EDEADLK;
@@ -468,7 +469,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
machine, (uint32_t) uid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -479,7 +480,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
/* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */
if (mapped < HOST_UID_LIMIT || mapped == uid)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
l = strlen(name);
if (buflen < l+1) {
@@ -497,13 +498,8 @@ enum nss_status _nss_mymachines_getpwnam_r(
pwd->pw_dir = (char*) "/";
pwd->pw_shell = (char*) "/sbin/nologin";
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -522,17 +518,18 @@ enum nss_status _nss_mymachines_getpwuid_r(
uint32_t mapped;
int r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
if (!uid_is_valid(uid))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
/* We consider all uids < 65536 host uids */
if (uid < HOST_UID_LIMIT)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (avoid_deadlock()) {
r = -EDEADLK;
@@ -554,7 +551,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
(uint32_t) uid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -564,7 +561,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
goto fail;
if (mapped == uid)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) {
*errnop = ERANGE;
@@ -579,13 +576,8 @@ enum nss_status _nss_mymachines_getpwuid_r(
pwd->pw_dir = (char*) "/";
pwd->pw_shell = (char*) "/sbin/nologin";
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -608,6 +600,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
size_t l;
int r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -615,25 +608,25 @@ enum nss_status _nss_mymachines_getgrnam_r(
p = startswith(name, "vg-");
if (!p)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
e = strrchr(p, '-');
if (!e || e == p)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
r = parse_gid(e + 1, &gid);
if (r < 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
machine = strndupa(p, e - p);
if (!machine_name_is_valid(machine))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (avoid_deadlock()) {
r = -EDEADLK;
@@ -655,7 +648,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
machine, (uint32_t) gid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -665,7 +658,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
goto fail;
if (mapped < HOST_GID_LIMIT || mapped == gid)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
l = sizeof(char*) + strlen(name) + 1;
if (buflen < l) {
@@ -681,13 +674,8 @@ enum nss_status _nss_mymachines_getgrnam_r(
gr->gr_passwd = (char*) "*"; /* locked */
gr->gr_mem = (char**) buffer;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -706,17 +694,18 @@ enum nss_status _nss_mymachines_getgrgid_r(
uint32_t mapped;
int r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
if (!gid_is_valid(gid))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
/* We consider all gids < 65536 host gids */
if (gid < HOST_GID_LIMIT)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (avoid_deadlock()) {
r = -EDEADLK;
@@ -738,7 +727,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
(uint32_t) gid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -748,7 +737,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
goto fail;
if (mapped == gid)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (buflen < sizeof(char*) + 1) {
*errnop = ERANGE;
@@ -766,13 +755,8 @@ enum nss_status _nss_mymachines_getgrgid_r(
gr->gr_passwd = (char*) "*"; /* locked */
gr->gr_mem = (char**) buffer;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index f67a28076c..a28b5d8ba8 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -122,6 +122,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
char *r_name;
int c, r, i = 0;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -159,20 +160,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
if (r < 0) {
- if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
- *errnop = ESRCH;
- *h_errnop = HOST_NOT_FOUND;
- return NSS_STATUS_NOTFOUND;
- }
+ if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
+ !bus_error_shall_fallback(&error))
+ goto not_found;
/* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
allowing falling back to other nss modules. Treat all other error conditions as
NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
case so that the nsswitch.conf configuration can distuingish such executed but
negative replies from complete failure to talk to resolved). */
- if (!bus_error_shall_fallback(&error))
- ret = NSS_STATUS_NOTFOUND;
-
goto fail;
}
@@ -181,11 +177,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
r = c;
goto fail;
}
- if (c == 0) {
- *errnop = ESRCH;
- *h_errnop = HOST_NOT_FOUND;
- return NSS_STATUS_NOTFOUND;
- }
+ if (c == 0)
+ goto not_found;
if (isempty(canonical))
canonical = name;
@@ -266,8 +259,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
if (ttlp)
*ttlp = 0;
- /* Explicitly reset all error variables */
- *errnop = 0;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
@@ -277,6 +270,10 @@ fail:
*errnop = -r;
*h_errnop = NO_RECOVERY;
return ret;
+
+not_found:
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
}
enum nss_status _nss_resolve_gethostbyname3_r(
@@ -297,6 +294,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
const char *canonical;
int c, r, i = 0;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -342,14 +340,9 @@ enum nss_status _nss_resolve_gethostbyname3_r(
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
if (r < 0) {
- if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
- *errnop = ESRCH;
- *h_errnop = HOST_NOT_FOUND;
- return NSS_STATUS_NOTFOUND;
- }
-
- if (!bus_error_shall_fallback(&error))
- ret = NSS_STATUS_NOTFOUND;
+ if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
+ !bus_error_shall_fallback(&error))
+ goto not_found;
goto fail;
}
@@ -359,11 +352,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
r = c;
goto fail;
}
- if (c == 0) {
- *errnop = ESRCH;
- *h_errnop = HOST_NOT_FOUND;
- return NSS_STATUS_NOTFOUND;
- }
+ if (c == 0)
+ goto not_found;
if (isempty(canonical))
canonical = name;
@@ -451,23 +441,27 @@ enum nss_status _nss_resolve_gethostbyname3_r(
result->h_length = alen;
result->h_addr_list = (char**) r_addr_list;
- /* Explicitly reset all error variables */
- *errnop = 0;
- *h_errnop = NETDB_SUCCESS;
- h_errno = 0;
-
if (ttlp)
*ttlp = 0;
if (canonp)
*canonp = r_name;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
+ *h_errnop = NETDB_SUCCESS;
+ h_errno = 0;
+
return NSS_STATUS_SUCCESS;
fail:
*errnop = -r;
*h_errnop = NO_RECOVERY;
return ret;
+
+not_found:
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
}
enum nss_status _nss_resolve_gethostbyaddr2_r(
@@ -488,6 +482,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
const char *n;
int r, ifindex;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(addr);
@@ -545,14 +540,9 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
if (r < 0) {
- if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
- *errnop = ESRCH;
- *h_errnop = HOST_NOT_FOUND;
- return NSS_STATUS_NOTFOUND;
- }
-
- if (!bus_error_shall_fallback(&error))
- ret = NSS_STATUS_NOTFOUND;
+ if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
+ !bus_error_shall_fallback(&error))
+ goto not_found;
goto fail;
}
@@ -578,11 +568,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
if (r < 0)
return r;
- if (c <= 0) {
- *errnop = ESRCH;
- *h_errnop = HOST_NOT_FOUND;
- return NSS_STATUS_NOTFOUND;
- }
+ if (c <= 0)
+ goto not_found;
ms += ALIGN(len) + /* the address */
2 * sizeof(char*) + /* pointers to the address, plus trailing NULL */
@@ -641,8 +628,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
if (ttlp)
*ttlp = 0;
- /* Explicitly reset all error variables */
- *errnop = 0;
+ /* Explicitly reset both *h_errnop and h_errno to work around
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
@@ -652,6 +639,10 @@ fail:
*errnop = -r;
*h_errnop = NO_RECOVERY;
return ret;
+
+not_found:
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
}
NSS_GETHOSTBYNAME_FALLBACKS(resolve);
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index f516b84c63..f554828d49 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -145,6 +145,7 @@ enum nss_status _nss_systemd_getpwnam_r(
size_t l;
int bypass, r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
@@ -153,26 +154,24 @@ enum nss_status _nss_systemd_getpwnam_r(
/* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
* generate EINVAL here, because it isn't really out business to complain about invalid user names. */
if (!valid_user_group_name(name))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
if (streq(name, root_passwd.pw_name)) {
*pwd = root_passwd;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (synthesize_nobody() &&
streq(name, nobody_passwd.pw_name)) {
*pwd = nobody_passwd;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
}
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
if (bypass <= 0) {
@@ -184,7 +183,7 @@ enum nss_status _nss_systemd_getpwnam_r(
if (bypass > 0) {
r = direct_lookup_name(name, (uid_t*) &translated);
if (r == -ENOENT)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
} else {
@@ -199,7 +198,7 @@ enum nss_status _nss_systemd_getpwnam_r(
name);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -225,13 +224,8 @@ enum nss_status _nss_systemd_getpwnam_r(
pwd->pw_dir = (char*) DYNAMIC_USER_DIR;
pwd->pw_shell = (char*) DYNAMIC_USER_SHELL;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -251,31 +245,30 @@ enum nss_status _nss_systemd_getpwuid_r(
size_t l;
int bypass, r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
if (!uid_is_valid(uid))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
/* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
if (uid == root_passwd.pw_uid) {
*pwd = root_passwd;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (synthesize_nobody() &&
uid == nobody_passwd.pw_uid) {
*pwd = nobody_passwd;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
}
if (!uid_is_dynamic(uid))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
if (bypass <= 0) {
@@ -287,7 +280,7 @@ enum nss_status _nss_systemd_getpwuid_r(
if (bypass > 0) {
r = direct_lookup_uid(uid, &direct);
if (r == -ENOENT)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
@@ -305,7 +298,7 @@ enum nss_status _nss_systemd_getpwuid_r(
(uint32_t) uid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -331,13 +324,8 @@ enum nss_status _nss_systemd_getpwuid_r(
pwd->pw_dir = (char*) DYNAMIC_USER_DIR;
pwd->pw_shell = (char*) DYNAMIC_USER_SHELL;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -358,31 +346,30 @@ enum nss_status _nss_systemd_getgrnam_r(
size_t l;
int bypass, r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(name);
assert(gr);
if (!valid_user_group_name(name))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
/* Synthesize records for root and nobody, in case they are missing form /etc/group */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
if (streq(name, root_group.gr_name)) {
*gr = root_group;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (synthesize_nobody() &&
streq(name, nobody_group.gr_name)) {
*gr = nobody_group;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
}
if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
if (bypass <= 0) {
@@ -394,7 +381,7 @@ enum nss_status _nss_systemd_getgrnam_r(
if (bypass > 0) {
r = direct_lookup_name(name, (uid_t*) &translated);
if (r == -ENOENT)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
} else {
@@ -409,7 +396,7 @@ enum nss_status _nss_systemd_getgrnam_r(
name);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -433,13 +420,8 @@ enum nss_status _nss_systemd_getgrnam_r(
gr->gr_passwd = (char*) DYNAMIC_USER_PASSWD;
gr->gr_mem = (char**) buffer;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -459,31 +441,30 @@ enum nss_status _nss_systemd_getgrgid_r(
size_t l;
int bypass, r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
if (!gid_is_valid(gid))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
if (gid == root_group.gr_gid) {
*gr = root_group;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (synthesize_nobody() &&
gid == nobody_group.gr_gid) {
*gr = nobody_group;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
}
}
if (!gid_is_dynamic(gid))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
if (bypass <= 0) {
@@ -495,7 +476,7 @@ enum nss_status _nss_systemd_getgrgid_r(
if (bypass > 0) {
r = direct_lookup_uid(gid, &direct);
if (r == -ENOENT)
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
@@ -513,7 +494,7 @@ enum nss_status _nss_systemd_getgrgid_r(
(uint32_t) gid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_DYNAMIC_USER))
- goto not_found;
+ return NSS_STATUS_NOTFOUND;
goto fail;
}
@@ -537,13 +518,8 @@ enum nss_status _nss_systemd_getgrgid_r(
gr->gr_passwd = (char*) DYNAMIC_USER_PASSWD;
gr->gr_mem = (char**) buffer;
- *errnop = 0;
return NSS_STATUS_SUCCESS;
-not_found:
- *errnop = 0;
- return NSS_STATUS_NOTFOUND;
-
fail:
*errnop = -r;
return NSS_STATUS_UNAVAIL;
@@ -598,6 +574,7 @@ static void systemd_endent(GetentData *data) {
}
static enum nss_status nss_systemd_endent(GetentData *p) {
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert_se(pthread_mutex_lock(&p->mutex) == 0);
@@ -668,6 +645,7 @@ static enum nss_status systemd_setent(GetentData *p) {
uid_t id;
int bypass, r;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(p);
@@ -750,6 +728,7 @@ enum nss_status _nss_systemd_getpwent_r(struct passwd *result, char *buffer, siz
UserEntry *p;
size_t len;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(result);
@@ -778,7 +757,6 @@ enum nss_status _nss_systemd_getpwent_r(struct passwd *result, char *buffer, siz
break;
}
if (!p) {
- *errnop = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto finalize;
}
@@ -801,6 +779,7 @@ enum nss_status _nss_systemd_getgrent_r(struct group *result, char *buffer, size
UserEntry *p;
size_t len;
+ PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
assert(result);
@@ -827,7 +806,6 @@ enum nss_status _nss_systemd_getgrent_r(struct group *result, char *buffer, size
break;
}
if (!p) {
- *errnop = ENOENT;
ret = NSS_STATUS_NOTFOUND;
goto finalize;
}
diff --git a/src/portable/portabled-image.c b/src/portable/portabled-image.c
index c58197c9a6..a6b3f52e99 100644
--- a/src/portable/portabled-image.c
+++ b/src/portable/portabled-image.c
@@ -58,7 +58,6 @@ int manager_image_cache_add(Manager *m, Image *image) {
*
* 2. If the image was discovered in the search path (i.e. its discoverable boolean set) we'll also add it
* under its short name.
- *
*/
r = manager_image_cache_initialize(m);
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 0a6f482cc1..e0d70c29cb 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -2143,7 +2143,6 @@ static int dnssec_test_positive_wildcard_nsec(
* 3) b.c.d.e.f
* 4) *.c.d.e.f
* 5) c.d.e.f
- *
*/
for (;;) {
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 5476ca2dbd..6645db467c 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -164,6 +164,8 @@ void dns_server_unlink(DnsServer *s) {
LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
s->manager->n_dns_servers--;
break;
+ default:
+ assert_not_reached("Unknown server type");
}
s->linked = false;
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index dffc4217d1..53d45a6361 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -13,8 +13,9 @@ typedef enum DnsServerType {
DNS_SERVER_SYSTEM,
DNS_SERVER_FALLBACK,
DNS_SERVER_LINK,
+ _DNS_SERVER_TYPE_MAX,
+ _DNS_SERVER_TYPE_INVALID = -1
} DnsServerType;
-#define _DNS_SERVER_TYPE_MAX (DNS_SERVER_LINK + 1)
const char* dns_server_type_to_string(DnsServerType i) _const_;
DnsServerType dns_server_type_from_string(const char *s) _pure_;
diff --git a/src/resolve/test-resolve-tables.c b/src/resolve/test-resolve-tables.c
index 842d42b311..2230a66ef5 100644
--- a/src/resolve/test-resolve-tables.c
+++ b/src/resolve/test-resolve-tables.c
@@ -1,11 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "dns-type.h"
+#include "resolved-dns-dnssec.h"
+#include "resolved-dns-packet.h"
#include "test-tables.h"
int main(int argc, char **argv) {
uint16_t i;
+ test_table(dns_protocol, DNS_PROTOCOL);
+ test_table(dnssec_result, DNSSEC_RESULT);
+ test_table(dnssec_verdict, DNSSEC_VERDICT);
+
+ test_table_sparse(dns_rcode, DNS_RCODE);
test_table_sparse(dns_type, DNS_TYPE);
log_info("/* DNS_TYPE */");
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index a405d22809..28b830bd41 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -422,16 +422,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return 1;
}
- r = parse_percent(eq);
+ r = parse_permille(eq);
if (r >= 0) {
char *n;
- /* When this is a percentage we'll convert this into a relative value in the range
- * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related
- * ones). This way the physical memory size can be determined server-side */
+ /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
+ * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
+ * size can be determined server-side. */
n = strjoina(field, "Scale");
- r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+ r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
if (r < 0)
return bus_log_create_error(r);
@@ -449,13 +449,15 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
if (isempty(eq))
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
else {
- r = parse_percent_unbounded(eq);
- if (r <= 0) {
- log_error_errno(r, "CPU quota '%s' invalid.", eq);
- return -EINVAL;
+ r = parse_permille_unbounded(eq);
+ if (r == 0) {
+ log_error("CPU quota too small.");
+ return -ERANGE;
}
+ if (r < 0)
+ return log_error_errno(r, "CPU quota '%s' invalid.", eq);
- r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (usec_t) r * USEC_PER_SEC / 100U);
+ r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
}
if (r < 0)
@@ -1189,7 +1191,7 @@ static int bus_append_kill_property(sd_bus_message *m, const char *field, const
return bus_append_parse_boolean(m, field, eq);
- if (streq(field, "KillSignal"))
+ if (STR_IN_SET(field, "KillSignal", "FinalKillSignal"))
return bus_append_signal_from_string(m, field, eq);
diff --git a/src/shared/initreq.h b/src/shared/initreq.h
index 9b19b5d729..e3ab3032cb 100644
--- a/src/shared/initreq.h
+++ b/src/shared/initreq.h
@@ -9,8 +9,8 @@
* version 2 of the License, or (at your option) any later version.
*
* Version: @(#)initreq.h 1.28 31-Mar-2004 MvS
- *
*/
+
#ifndef _INITREQ_H
#define _INITREQ_H
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 9c80f2b855..cb1d43c828 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -64,7 +64,6 @@ shared_sources = files('''
machine-pool.c
machine-pool.h
module-util.h
- module-util.c
nsflags.c
nsflags.h
output-mode.c
@@ -125,6 +124,10 @@ if conf.get('HAVE_LIBIPTC') == 1
shared_sources += files('firewall-util.c')
endif
+if conf.get('HAVE_KMOD') == 1
+ shared_sources += files('module-util.c')
+endif
+
libshared_name = 'systemd-shared-@0@'.format(meson.project_version())
libshared_deps = [threads,
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index d698b42e07..b5f22c8d1e 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -21,7 +21,6 @@
/*
* Generic infrastructure for replacing %x style specifiers in
* strings. Will call a callback for each replacement.
- *
*/
/* Any ASCII character or digit: our pool of potential specifiers,
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 6f8934eef0..64584e4a86 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3149,7 +3149,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
(void) check_triggering_units(bus, *name);
}
- if (r >= 0 && arg_wait) {
+ if (r >= 0 && arg_wait && !set_isempty(wait_context.unit_paths)) {
int q;
q = sd_event_loop(wait_context.event);
if (q < 0)
@@ -4927,7 +4927,7 @@ typedef enum SystemctlShowMode{
_SYSTEMCTL_SHOW_MODE_INVALID = -1,
} SystemctlShowMode;
-static const char* const systemctl_show_mode_table[] = {
+static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
[SYSTEMCTL_SHOW_PROPERTIES] = "show",
[SYSTEMCTL_SHOW_STATUS] = "status",
[SYSTEMCTL_SHOW_HELP] = "help",
diff --git a/src/test/meson.build b/src/test/meson.build
index 7da7e3a22c..18f05b2dc2 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -645,7 +645,7 @@ tests += [
[['src/test/test-nss.c'],
[],
[libdl],
- '', 'manual'],
+ 'ENABLE_NSS', 'manual'],
[['src/test/test-umount.c',
'src/core/mount-setup.c',
diff --git a/src/test/test-nss.c b/src/test/test-nss.c
index 9e543e7557..e0e7bb300d 100644
--- a/src/test/test-nss.c
+++ b/src/test/test-nss.c
@@ -431,13 +431,13 @@ static int parse_argv(int argc, char **argv,
modules = strv_new(argv[1], NULL);
else
modules = strv_new(
-#if ENABLE_MYHOSTNAME
+#if ENABLE_NSS_MYHOSTNAME
"myhostname",
#endif
-#if ENABLE_RESOLVE
+#if ENABLE_NSS_RESOLVE
"resolve",
#endif
-#if ENABLE_MACHINED
+#if ENABLE_NSS_MYMACHINES
"mymachines",
#endif
"dns",
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index 7f3f502c56..1b3b357913 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -206,15 +206,21 @@ static void test_get_process_cmdline_harder(void) {
assert_se(pid == 0);
assert_se(unshare(CLONE_NEWNS) >= 0);
- assert_se(mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) >= 0);
+ if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
+ log_warning_errno(errno, "mount(..., \"/\", MS_SLAVE|MS_REC, ...) failed: %m");
+ assert_se(IN_SET(errno, EPERM, EACCES));
+ return;
+ }
fd = mkostemp(path, O_CLOEXEC);
assert_se(fd >= 0);
+ /* Note that we don't unmount the following bind-mount at the end of the test because the kernel
+ * will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
/* This happens under selinux… Abort the test in this case. */
log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
- assert(errno == EACCES);
+ assert_se(IN_SET(errno, EPERM, EACCES));
return;
}
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 944104a25a..49268eae22 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -5,6 +5,7 @@
#include "cgroup.h"
#include "compress.h"
#include "condition.h"
+#include "device-internal.h"
#include "device.h"
#include "execute.h"
#include "import-util.h"
@@ -24,6 +25,7 @@
#include "rlimit-util.h"
#include "scope.h"
#include "service.h"
+#include "show-status.h"
#include "slice.h"
#include "socket-util.h"
#include "socket.h"
@@ -47,7 +49,9 @@ int main(int argc, char **argv) {
test_table(collect_mode, COLLECT_MODE);
test_table(condition_result, CONDITION_RESULT);
test_table(condition_type, CONDITION_TYPE);
+ test_table(device_action, DEVICE_ACTION);
test_table(device_state, DEVICE_STATE);
+ test_table(dns_over_tls_mode, DNS_OVER_TLS_MODE);
test_table(dnssec_mode, DNSSEC_MODE);
test_table(emergency_action, EMERGENCY_ACTION);
test_table(exec_directory_type, EXEC_DIRECTORY_TYPE);
@@ -75,6 +79,7 @@ int main(int argc, char **argv) {
test_table(name_policy, NAMEPOLICY);
test_table(namespace_type, NAMESPACE_TYPE);
test_table(notify_access, NOTIFY_ACCESS);
+ test_table(notify_state, NOTIFY_STATE);
test_table(output_mode, OUTPUT_MODE);
test_table(partition_designator, PARTITION_DESIGNATOR);
test_table(path_result, PATH_RESULT);
@@ -91,6 +96,7 @@ int main(int argc, char **argv) {
test_table(service_result, SERVICE_RESULT);
test_table(service_state, SERVICE_STATE);
test_table(service_type, SERVICE_TYPE);
+ test_table(show_status, SHOW_STATUS);
test_table(slice_state, SLICE_STATE);
test_table(socket_address_bind_ipv6_only, SOCKET_ADDRESS_BIND_IPV6_ONLY);
test_table(socket_exec_command, SOCKET_EXEC_COMMAND);
diff --git a/src/time-wait-sync/time-wait-sync.c b/src/time-wait-sync/time-wait-sync.c
index 90efe2bc19..e359e35e49 100644
--- a/src/time-wait-sync/time-wait-sync.c
+++ b/src/time-wait-sync/time-wait-sync.c
@@ -1,7 +1,6 @@
/*
* systemd service to wait until kernel realtime clock is synchronized
*
- *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index f3f76c16d2..b08588baf7 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -3,7 +3,6 @@
* ata_id - reads product/serial number from ATA drives
*
* Copyright © 2009-2010 David Zeuthen <zeuthen@gmail.com>
- *
*/
#include <ctype.h>
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 1aaa263f76..ee75bca37c 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* cdrom_id - optical drive and media information prober
- *
- *
*/
#include <errno.h>
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
index a88dedd002..82b8354763 100644
--- a/src/udev/collect/collect.c
+++ b/src/udev/collect/collect.c
@@ -17,7 +17,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
- *
*/
#include <errno.h>
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
index 5caab7774f..1600666730 100644
--- a/src/udev/scsi_id/scsi_id.c
+++ b/src/udev/scsi_id/scsi_id.c
@@ -2,7 +2,6 @@
/*
* Copyright © IBM Corp. 2003
* Copyright © SUSE Linux Products GmbH, 2006
- *
*/
#include <ctype.h>
diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h
index 1222f250ec..14e1663990 100644
--- a/src/udev/scsi_id/scsi_id.h
+++ b/src/udev/scsi_id/scsi_id.h
@@ -3,7 +3,6 @@
/*
* Copyright © IBM Corp. 2003
- *
*/
#define MAX_PATH_LEN 512
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index fd91657a32..7329ae0682 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -3,7 +3,6 @@
* Copyright © IBM Corp. 2003
*
* Author: Patrick Mansfield<patmans@us.ibm.com>
- *
*/
#include <errno.h>
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index 477b7ef61f..202efda3fe 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -3,7 +3,6 @@
* probe disks for filesystems and partitions
*
* Copyright © 2011 Karel Zak <kzak@redhat.com>
- *
*/
#include <blkid.h>
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index e428003ddc..f7616987ab 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -4,7 +4,6 @@
*
* Portions Copyright © 2004 David Zeuthen, <david@fubar.dk>
* Copyright © 2014 Carlos Garnacho <carlosg@gnome.org>
- *
*/
#include <errno.h>
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
index 5e9fd0ce43..f148d9c5f6 100644
--- a/src/udev/udev-builtin-kmod.c
+++ b/src/udev/udev-builtin-kmod.c
@@ -3,7 +3,6 @@
* load kernel modules
*
* Copyright © 2011 ProFUSION embedded systems
- *
*/
#include <errno.h>
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index 36f1949c7b..1688cae238 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -2,9 +2,7 @@
/*
* compose persistent device path
*
- *
* Logic based on Hannes Reinecke's shell script.
- *
*/
#include <ctype.h>
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index b1191ae7ff..4ddd89dbb1 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* manage device node user ACL
- *
- *
*/
#include <errno.h>
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index dcf21a2f44..97548e92ed 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -4,8 +4,6 @@
*
* Copyright (c) 2005 SUSE Linux Products GmbH, Germany
* Author: Hannes Reinecke <hare@suse.de>
- *
- *
*/
#include <ctype.h>
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index efe7297f04..420e841764 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -2,7 +2,6 @@
*
* libudev - interface to udev device information
*
- *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index fd8406d959..541aac2c3f 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <ctype.h>
#include <errno.h>
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 333dcae6b9..c3bfe8b00c 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <errno.h>
#include <fcntl.h>
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index f029395884..f9eff70295 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <ctype.h>
#include <errno.h>
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index 7864f57aa5..1ae89334bb 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -2,7 +2,6 @@
/*
* Copyright © 2009 Canonical Ltd.
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>
- *
*/
#include <errno.h>
diff --git a/src/udev/udev.h b/src/udev/udev.h
index 4596d0ea01..778d5c4174 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -3,7 +3,6 @@
/*
* Copyright © 2003 Greg Kroah-Hartman <greg@kroah.com>
- *
*/
#include <sys/param.h>
diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c
index a84cc156cb..7f89d4f536 100644
--- a/src/udev/udevadm-control.c
+++ b/src/udev/udevadm-control.c
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index ff41290478..e0c110135a 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <ctype.h>
#include <errno.h>
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index b1e13553dc..d44b1fe521 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <errno.h>
#include <getopt.h>
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
index b8d428bcb4..33173522fe 100644
--- a/src/udev/udevadm-settle.c
+++ b/src/udev/udevadm-settle.c
@@ -2,7 +2,6 @@
/*
* Copyright © 2009 Canonical Ltd.
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>
- *
*/
#include <errno.h>
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 0d6cd46bd7..c19ba4b45f 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <errno.h>
#include <getopt.h>
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index e3d85597a8..73bb2124fc 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright © 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
- *
*/
#include <errno.h>
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 9c07a51869..21c43af18a 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <errno.h>
#include <fcntl.h>
diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c
index c570b72b8e..0e8a820a56 100644
--- a/src/udev/udevadm-util.c
+++ b/src/udev/udevadm-util.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include "path-util.h"
#include "string-util.h"
diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h
index 0b426e09f6..f843e60c61 100644
--- a/src/udev/udevadm-util.h
+++ b/src/udev/udevadm-util.h
@@ -1,9 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#pragma once
-/*
- */
-
#include "udev.h"
struct udev_device *find_device(struct udev *udev,
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index 0b79d2f91d..a4d3c6e77f 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -1,7 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- *
- */
#include <errno.h>
#include <getopt.h>
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 34f6a95503..264a91a32a 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -3,7 +3,6 @@
* Copyright © 2004 Chris Friesen <chris_friesen@sympatico.ca>
* Copyright © 2009 Canonical Ltd.
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>
- *
*/
#include <errno.h>
diff --git a/test/TEST-23-TYPE-EXEC/Makefile b/test/TEST-23-TYPE-EXEC/Makefile
new file mode 100644
index 0000000000..34d7cc6cdf
--- /dev/null
+++ b/test/TEST-23-TYPE-EXEC/Makefile
@@ -0,0 +1,4 @@
+BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
+
+all setup clean run:
+ @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
diff --git a/test/TEST-23-TYPE-EXEC/test.sh b/test/TEST-23-TYPE-EXEC/test.sh
new file mode 100755
index 0000000000..bdcea239a7
--- /dev/null
+++ b/test/TEST-23-TYPE-EXEC/test.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -e
+TEST_DESCRIPTION="test Type=exec"
+
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+ cp testsuite.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-23-TYPE-EXEC/testsuite.sh b/test/TEST-23-TYPE-EXEC/testsuite.sh
new file mode 100755
index 0000000000..80734bbbdc
--- /dev/null
+++ b/test/TEST-23-TYPE-EXEC/testsuite.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -ex
+set -o pipefail
+
+systemd-analyze set-log-level debug
+systemd-analyze set-log-target console
+
+# Create a binary for which execve() will fail
+touch /tmp/brokenbinary
+chmod +x /tmp/brokenbinary
+
+# These three commands should succeed.
+systemd-run --unit=one -p Type=simple /bin/sleep infinity
+systemd-run --unit=two -p Type=simple -p User=idontexist /bin/sleep infinity
+systemd-run --unit=three -p Type=simple /tmp/brokenbinary
+
+# And now, do the same with Type=exec, where the latter two should fail
+systemd-run --unit=four -p Type=exec /bin/sleep infinity
+! systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity
+! systemd-run --unit=six -p Type=exec /tmp/brokenbinary
+
+systemd-analyze set-log-level info
+
+echo OK > /testok
+
+exit 0
diff --git a/tools/check-includes.pl b/tools/check-includes.pl
index 6aae7c1534..c8bfcba8c0 100755
--- a/tools/check-includes.pl
+++ b/tools/check-includes.pl
@@ -1,7 +1,7 @@
+# SPDX-License-Identifier: CC0-1.0
#!/usr/bin/env perl
#
# checkincludes: Find files included more than once in (other) files.
-# Copyright abandoned, 2000, Niels Kristian Bech Jensen <nkbj@image.dk>.
foreach $file (@ARGV) {
open(FILE, $file) or die "Cannot open $file: $!.\n";
diff --git a/tools/meson-build.sh b/tools/meson-build.sh
index 304a755676..317dad932d 100755
--- a/tools/meson-build.sh
+++ b/tools/meson-build.sh
@@ -6,7 +6,7 @@ dst="$2"
target="$3"
options="$4"
-[ -d "$dst" ] || meson "$src" "$dst" $options
+[ -f "$dst/ninja.build" ] || meson "$src" "$dst" $options
# Locate ninja binary, on CentOS 7 it is called ninja-build, so
# use that name if available.
diff --git a/tools/meson-link-test.c b/tools/meson-link-test.c
deleted file mode 100644
index 825bbff05f..0000000000
--- a/tools/meson-link-test.c
+++ /dev/null
@@ -1 +0,0 @@
-int main(void) {return 0;}
diff --git a/units/user-.slice.d/10-defaults.conf b/units/user-.slice.d/10-defaults.conf
index 95ab11b30b..f1d118562c 100644
--- a/units/user-.slice.d/10-defaults.conf
+++ b/units/user-.slice.d/10-defaults.conf
@@ -9,6 +9,7 @@
[Unit]
Description=User Slice of UID %j
+Documentation=man:user@.service(5)
After=systemd-user-sessions.service
[Slice]
diff --git a/units/user-runtime-dir@.service.in b/units/user-runtime-dir@.service.in
index 8c02beda3b..3a852b68a6 100644
--- a/units/user-runtime-dir@.service.in
+++ b/units/user-runtime-dir@.service.in
@@ -9,6 +9,7 @@
[Unit]
Description=/run/user/%i mount wrapper
+Documentation=man:user@.service(5)
StopWhenUnneeded=yes
[Service]
diff --git a/units/user@.service.in b/units/user@.service.in
index b88108e1b7..f840c4114c 100644
--- a/units/user@.service.in
+++ b/units/user@.service.in
@@ -9,8 +9,8 @@
[Unit]
Description=User Manager for UID %i
-After=systemd-user-sessions.service
-After=user-runtime-dir@%i.service
+Documentation=man:user@.service(5)
+After=systemd-user-sessions.service user-runtime-dir@%i.service dbus.service
Requires=user-runtime-dir@%i.service
[Service]