summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2018-07-19 12:42:57 -0400
committerLuke Shumaker <lukeshu@lukeshu.com>2018-07-19 12:42:57 -0400
commit52f5927b80febce2366e23fa4bce629e8df44efb (patch)
treeda608743f96af21ccd9acdfe71251ca5c472595f
parentc9bb7ae80d1a888cd717c891f4be1b7f3030772f (diff)
parent361d6b31f68cc22498d478fb4709391e83ab8c4c (diff)
Merge tag 'systemd/v238.133-4.parabola1' into systemd/parabola
-rw-r--r--README9
-rw-r--r--doc/CGROUP_DELEGATION.md445
-rw-r--r--doc/UIDS-GIDS.md35
-rw-r--r--hwdb/60-evdev.hwdb7
-rw-r--r--hwdb/60-keyboard.hwdb7
-rw-r--r--hwdb/60-sensor.hwdb6
-rw-r--r--man/file-hierarchy.xml31
-rw-r--r--man/loginctl.xml8
-rw-r--r--man/os-release.xml3
-rw-r--r--man/systemd-detect-virt.xml6
-rw-r--r--man/systemd-escape.xml2
-rw-r--r--man/systemd-journal-upload.xml4
-rw-r--r--man/systemd-networkd-wait-online.service.xml2
-rw-r--r--man/systemd.exec.xml35
-rw-r--r--man/systemd.special.xml42
-rw-r--r--man/systemd.unit.xml12
-rw-r--r--man/udevadm.xml10
-rw-r--r--meson.build6
-rw-r--r--src/activate/activate.c2
-rw-r--r--src/basic/audit-util.c7
-rw-r--r--src/basic/btrfs-util.c2
-rw-r--r--src/basic/cgroup-util.c4
-rw-r--r--src/basic/fd-util.c15
-rw-r--r--src/basic/fileio.c13
-rw-r--r--src/basic/fs-util.c13
-rw-r--r--src/basic/log.c19
-rw-r--r--src/basic/missing_syscall.h8
-rw-r--r--src/basic/virt.c13
-rw-r--r--src/boot/efi/meson.build21
-rw-r--r--src/core/bpf-firewall.c5
-rw-r--r--src/core/dbus-cgroup.c15
-rw-r--r--src/core/device.c4
-rw-r--r--src/core/execute.c19
-rw-r--r--src/core/mount-setup.c42
-rw-r--r--src/core/shutdown.c24
-rw-r--r--src/core/umount.c198
-rw-r--r--src/core/umount.h6
-rw-r--r--src/import/import.c2
-rw-r--r--src/login/logind-dbus.c2
-rw-r--r--src/network/netdev/netdev.c2
-rw-r--r--src/network/networkd-dhcp4.c5
-rw-r--r--src/network/networkd-dhcp6.c4
-rw-r--r--src/network/networkd-link.c2
-rw-r--r--src/network/networkd-route.c10
-rw-r--r--src/shared/bus-unit-util.c2
-rw-r--r--src/shared/conf-parser.c21
-rw-r--r--src/systemctl/systemctl.c19
-rw-r--r--src/systemd/sd-bus-vtable.h3
-rw-r--r--src/test/test-conf-parser.c20
-rw-r--r--src/tmpfiles/tmpfiles.c5
-rw-r--r--src/udev/net/ethtool-util.c2
-rw-r--r--units/systemd-binfmt.service.in3
-rw-r--r--units/systemd-initctl.service.in2
-rw-r--r--units/systemd-initctl.socket4
54 files changed, 919 insertions, 289 deletions
diff --git a/README b/README
index b735214e2e..4a561a65cb 100644
--- a/README
+++ b/README
@@ -232,14 +232,11 @@ USERS AND GROUPS:
groups "wheel" and "adm" will be given read-only access to
journal files using systemd-tmpfiles.service.
- The journal gateway daemon requires the
- "systemd-journal-gateway" system user and group to
+ The journal remote daemon requires the
+ "systemd-journal-remote" system user and group to
exist. During execution this network facing service will drop
privileges and assume this uid/gid for security reasons.
- Similarly, the NTP daemon requires the "systemd-timesync" system
- user and group to exist.
-
Similarly, the network management daemon requires the
"systemd-network" system user and group to exist.
@@ -275,7 +272,7 @@ NSS:
passwd: compat mymachines systemd
group: compat mymachines systemd
- hosts: files mymachines resolve myhostname
+ hosts: files mymachines resolve [!UNAVAIL=return] dns myhostname
SYSV INIT.D SCRIPTS:
When calling "systemctl enable/disable/is-enabled" on a unit which is a
diff --git a/doc/CGROUP_DELEGATION.md b/doc/CGROUP_DELEGATION.md
new file mode 100644
index 0000000000..619c871212
--- /dev/null
+++ b/doc/CGROUP_DELEGATION.md
@@ -0,0 +1,445 @@
+# Control Group APIs and Delegation
+
+*Intended audience: hackers working on userspace subsystems that require direct
+cgroup access, such as container managers and similar.*
+
+So you are wondering about resource management with systemd, you know Linux
+control groups (cgroups) a bit and are trying to integrate your software with
+what systemd has to offer there. Here's a bit of documentation about the
+concepts and interfaces involved with this.
+
+What's described here has been part of systemd and documented since v205
+times. However, it has been updated and improved substantially since, even
+though the concepts stayed mostly the same. This is an attempt to provide more
+comprehensive up-to-date information about all this, particular in light of the
+poor implementations of the components interfacing with systemd of current
+container managers.
+
+Before you read on, please make sure you read the low-level [kernel
+documentation about
+cgroupsv2](https://www.kernel.org/doc/Documentation/cgroup-v2.txt). This
+documentation then adds in the higher-level view from systemd.
+
+This document augments the existing documentation we already have:
+
+* [The New Control Group Interfaces](https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/)
+* [Writing VM and Container Managers](https://www.freedesktop.org/wiki/Software/systemd/writing-vm-managers/)
+
+These wiki documents are not as up to date as they should be, currently, but
+the basic concepts still fully apply. You should read them too, if you do something
+with cgroups and systemd, in particular as they shine more light on the various
+D-Bus APIs provided. (That said, sooner or later we should probably fold that
+wiki documentation into this very document, too.)
+
+## Two Key Design Rules
+
+Much of the philosophy behind these concepts is based on a couple of basic
+design ideas of cgroupsv2 (which we however try to adapt as far as we can to
+cgroupsv1 too). Specifically two cgroupsv2 rules are the most relevant:
+
+1. The **no-processes-in-inner-nodes** rule: this means that it's not permitted
+to have processes directly attached to a cgroup that also has child cgroups and
+vice versa. A cgroup is either an inner node or a leaf node of the tree, and if
+it's an inner node it may not contain processes directly, and if it's a leaf
+node then it may not have child cgroups. (Note that there are some minor
+exceptions to this rule, though. i.e. the root cgroup is special and allows
+both processes and children — which is used in particular to maintain kernel
+threads.)
+
+2. The **single-writer** rule: this means that each cgroup only has a single
+writer, i.e. a single process managing it. It's OK if different cgroups have
+different processes managing them. However, only a single process should own a
+specific cgroup, and when it does that ownership is exclusive, and nothing else
+should manipulate it at the same time. This rule ensures that various pieces of
+software don't step on each other's toes constantly.
+
+These two rules have various effects. For example, one corollary of this is: if
+your container manager creates and manages cgroups in the system's root cgroup
+you violate rule #2, as the root cgroup is managed by systemd and hence off
+limits to everybody else.
+
+Note that rule #1 is generally enforced by the kernel if cgroupsv2 is used: as
+soon as you add a process to a cgroup it is ensured the rule is not
+violated. On cgroupsv1 this rule didn't exist, and hence isn't enforced, even
+though it's a good thing to follow it then too. Rule #2 is not enforced on
+either cgroupsv1 nor cgroupsv2 (this is UNIX after all, in the general case
+root can do anything, modulo SELinux and friends), but if you ignore it you'll
+be in constant pain as various pieces of software will fight over cgroup
+ownership.
+
+Note that cgroupsv1 is currently the most deployed implementation of all of
+this, even though it's semantically broken in many ways, and in many cases
+doesn't actually do what people think it does. cgroupsv2 is where things are
+going, and most new kernel features in this area are only added to cgroupsv2,
+and not cgroupsv1 anymore. For example cgroupsv2 provides proper cgroup-empty
+notifications, has support for all kinds of per-cgroup BPF magic, supports
+secure delegation of cgroup trees to less privileged processes and so on, which
+all are not available on cgroupsv1.
+
+## Three Different Tree Setups 🌳
+
+systemd supports three different modes how cgroups are set up. Specifically:
+
+1. **Unified** — this is the simplest mode, and exposes a pure cgroupsv2
+logic. In this mode `/sys/fs/cgroup` is the only mounted cgroup API file system
+and all available controllers are exclusively exposed through it.
+
+2. **Legacy** — this is the traditional cgroupsv1 mode. In this mode the
+various controllers each get their own cgroup file system mounted to
+`/sys/fs/cgroup/<controller>/`. On top of that systemd manages its own cgroup
+hierarchy for managing purposes as `/sys/fs/cgroup/systemd/`.
+
+3. **Hybrid** — this is a hybrid between the unified and legacy mode. It's set
+up mostly like legacy, except that there's also an additional hierarchy
+`/sys/fs/cgroup/unified/` that contains the cgroupsv2 hierarchy. In this mode
+compatibility with cgroupsv1 is retained while some cgroupsv2 features are
+available too. This mode is a stopgap. Don't bother with this too much unless
+you have too much free time.
+
+To say this clearly, legacy and hybrid modes have no future. If you develop
+software today and don't focus on the unified mode, then you are writing
+software for yesterday, not tomorrow. They are primarily supported for
+compatibility reasons and will not receive new features. Sorry.
+
+Superficially, in legacy and hybrid modes it might appear that the parallel
+cgroup hierarchies for each controller are orthogonal from each other. In
+systemd they are not: the hierarchies of all controllers are always kept in
+sync (at least mostly: sub-trees might be suppressed in certain hierarchies if
+no controller usage is required for them). The fact that systemd keeps these
+hierarchies in sync means that the legacy and hybrid hierarchies are
+conceptually very close to the unified hierarchy. In particular this allows us
+talk of one specific cgroup and actually mean the same cgroup in all available
+controller hierarchies. e.g. if we talk about the cgroup `/foo/bar/` then we
+actually mean `/sys/fs/cgroup/cpu/foo/bar/` as well as
+`/sys/fs/cgroup/memory/foo/bar/`, `/sys/fs/cgroup/pids/foo/bar/`, and so on, in
+one. Note that in cgroupsv2 the controller hierarchies aren't orthogonal, hence
+thinking about them as orthogonal won't help you in the long run anyway.
+
+If you wonder how to detect which of these three modes is currently used, use
+`statfs()` on `/sys/fs/cgroup/`. If it reports `CGROUP2_SUPER_MAGIC` in its
+`.f_type` field, then you are in unified mode. If it reports `TMPFS_MAGIC` then
+you are either in legacy or hybrid mode. To distuingish these two cases, run
+`statfs()` again on `/sys/fs/cgroup/unified/`. If that succeeds and reports
+`CGROUP2_SUPER_MAGIC` you are in hybrid mode, otherwise not.
+
+## systemd's Unit Types
+
+The low-level kernel cgroups feature is exposed in systemd in three different
+"unit" types. Specifically:
+
+1. 💼 The `.service` unit type. This unit type is for units encapsulating
+ processes systemd itself starts. Units of these types have cgroups that are
+ the leaves of the cgroup tree the systemd instance manages (though possibly
+ they might contain a sub-tree of their own managed by something else, made
+ possible by the concept of delegation, see below). Service units are usually
+ instantiated based on a unit file on disk that describes the command line to
+ invoke and other properties of the service. However, service units may also
+ be declared and started programmatically at runtime through a D-Bus API
+ (which is called *transient* services).
+
+2. 👓 The `.scope` unit type. This is very similar to `.service`. The main
+ difference: the processes the units of this type encapsulate are forked off
+ by some unrelated manager process, and that manager asked systemd to expose
+ them as a unit. Unlike services, scopes can only be declared and started
+ programmatically, i.e. are always transient. That's because they encapsulate
+ processes forked off by something else, i.e. existing runtime objects, and
+ hence cannot really be defined fully in 'offline' concepts such as unit
+ files.
+
+3. 🔪 The `.slice` unit type. Units of this type do not directly contain any
+ processes. Units of this type are the inner nodes of part of the cgroup tree
+ the systemd instance manages. Much like services, slices can be defined
+ either on disk with unit files or programmatically as transient units.
+
+Slices expose the trunk and branches of a tree, and scopes and services are
+attached to those branches as leaves. The idea is that scopes and services can
+be moved around though, i.e. assigned to a different slice if needed.
+
+The naming of slice units directly maps to the cgroup tree path. This is not
+the case for service and scope units however. A slice named `foo-bar-baz.slice`
+maps to a cgroup `/foo.slice/foo-bar.slice/foo-bar-baz.slice/`. A service
+`quux.service` which is attached to the slice `foo-bar-baz.slice` maps to the
+cgroup `/foo.slice/foo-bar.slice/foo-bar-baz.slice/quux.service/`.
+
+By default systemd sets up four slice units:
+
+1. `-.slice` is the root slice. i.e. the parent of everything else. On the host
+ system it maps directly to the top-level directory of cgroupsv2.
+
+2. `system.slice` is where system services are by default placed, unless
+ configured otherwise.
+
+3. `user.slice` is where user sessions are placed. Each user gets a slice of
+ its own below that.
+
+4. `machines.slice` is where VMs and containers are supposed to be
+ placed. `systemd-nspawn` makes use of this by default, and you're very welcome
+ to place your containers and VMs there too if you hack on managers for those.
+
+Users may define any amount of additional slices they like though, the four
+above are just the defaults.
+
+## Delegation
+
+Container managers and suchlike often want to control cgroups directly using
+the raw kernel APIs. That's entirely fine and supported, as long as proper
+*delegation* is followed. Delegation is a concept we inherited from cgroupsv2,
+but we expose it on cgroupsv1 too. Delegation means that some parts of the
+cgroup tree may be managed by different managers than others. As long as it is
+clear which manager manages which part of the tree each one can do within its
+sub-graph of the tree whatever it wants.
+
+Only sub-trees can be delegated (though whoever decides to request a sub-tree
+can delegate sub-sub-trees further to somebody else if they like
+it). Delegation takes place at a specific cgroup: in systemd there's a
+`Delegate=` property you can set for a service or scope unit. If you do, it's
+the cut-off point for systemd's cgroup management: the unit itself is managed
+by systemd, i.e. all its attributes are managed exclusively by systemd, however
+your program may create/remove sub-cgroups inside it freely, and those then
+become exclusive property of your program, systemd won't touch them — all
+attributes of *those* sub-cgroups can be manipulated freely and exclusively by
+your program.
+
+By turning on the `Delegate=` property for a scope or service you get a few
+guarantees:
+
+1. systemd won't fiddle with your sub-tree of the cgroup tree anymore. It won't
+ change attributes of any cgroups below it, nor will it create or remove any
+ cgroups thereunder, nor migrate processes across the boundaries of that
+ sub-tree as it deems useful anymore.
+
+2. If your service makes use of the `User=` functionality, then the sub-tree
+ will be `chown()`ed to the indicated user so that it can correctly create
+ cgroups below it. Note however that systemd will do that only in the unified
+ hierarchy (in unified and hybrid mode) as well as on systemd's own private
+ hierarchy (in legacy and hybrid mode). It won't pass ownership of the legacy
+ controller hierarchies. Delegation to less privileges processes is not safe
+ in cgroupsv1 (as a limitation of the kernel), hence systemd won't facilitate
+ access to it.
+
+3. Any BPF IP filter programs systemd installs will be installed with
+ `BPF_F_ALLOW_MULTI` so that your program can install additional ones.
+
+In unit files the `Delegate=` property is superficially exposed as
+boolean. However, since v236 it optionally takes a list of controller names
+instead. If so, delegation is requested for listed controllers
+specifically. Note hat this only encodes a request. Depending on various
+parameters it might happen that your service actually will get fewer
+controllers delegated (for example, because the controller is not available on
+the current kernel or was turned off) or more. If no list is specified
+(i.e. the property simply set to `yes`) then all available controllers are
+delegated.
+
+Let's stress one thing: delegation is available on scope and service units
+only. It's expressly not available on slice units. Why that? Because slice
+units are our *inner* nodes of the cgroup trees and we freely attach service
+and scopes to them. If we'd allow delegation on slice units then this would
+mean that that both systemd and your own manager would create/delete cgroups
+below the slice unit and that conflicts with the single-writer rule.
+
+So, if you want to do your own raw cgroups kernel level access, then allocate a
+scope unit, or a service unit (or just use the service unit you already have
+for your service code), and turn on delegation for it.
+
+## Three Scenarios
+
+Let's say you write a container manager, and you wonder what to do regarding
+cgroups for it, as you want your manager to be able to run on systemd systems.
+
+You basically have three options:
+
+1. 😊 The *integration-is-good* option. For this, you register each container you
+ have either as systemd service (i.e. let systemd invoke the executor binary
+ for you) or systemd scope (i.e. your manager executes the binary directly,
+ but then tells systemd about it. In this mode the administrator can use the
+ usual systemd resource management commands individually on containers. By
+ turning on `Delegate=` for these scopes or services you make it possible to
+ run cgroup-enabled programs in your containers, for example a systemd
+ instance running inside it. This option has two sub-options:
+
+ a. You register the service or scope transiently directly by contacting
+ systemd via D-Bus. In this case systemd will just manage the unit for you and
+ nothing else.
+
+ b. Instead you register the service or scope through `systemd-machined`
+ (also via D-Bus). This mini-daemon is basically just a proxy for the same
+ operations as in a. The main benefit of this: this way you let the system
+ know that what you are registering is a container, and this opens up
+ certain additional integration points. For example, `journalctl -M` can
+ then be used to directly look into any container's journal logs (should
+ the container run systemd inside), or `systemctl -M` can be used to
+ directly invoke systemd operations inside the containers. Moreover tools
+ like "ps" can then show you to which container a process belongs (`ps -eo
+ pid,comm,machine`), and even gnome-system-monitor supports it.
+
+2. 🙁 The *i-like-islands* option. If all you care about is your own cgroup tree,
+ and you want to have to do as little as possible with systemd and no
+ interest in integration with the rest of the system, then this is a valid
+ option. For this all you have to do is turn on `Delegate=` for your main
+ manager daemon. Then figure out the cgroup systemd placed your daemon in:
+ you can now freely create sub-cgroups beneath it. Don't forget the
+ *no-processes-in-inner-nodes* rule however: you have to move your main
+ daemon process out of that cgroup (and into a sub-cgroup) before you can
+ start further processes in any of your sub-cgroups.
+
+3. 🙁 The *i-like-continents* option. In this option you'd leave your manager
+ daemon where it is, and would not turn on delegation on its unit. However,
+ as first thing you register a new scope unit with systemd, and that scope
+ unit would have `Delegate=` turned on, and then you place all your
+ containers underneath it. From systemd's PoV there'd be two units: your
+ manager service and the big scope that contains all your containers in one.
+
+BTW: if for whatever reason you say "I hate D-Bus, I'll never call any D-Bus
+API, kthxbye", then options #1 and #3 are not available, as they generally
+involve talking to systemd from your program code, via D-Bus. You still have
+option #2 in that case however, as you can simply set `Delegate=` in your
+service's unit file and you are done and have your own sub-tree. In fact, #2 is
+the one option that allows you to completely ignore systemd's existence: you
+can entirely generically follow the single rule that you just use the cgroup
+you are started in, and everything below it, whatever that might be. That said,
+maybe if you dislike D-Bus and systemd that much, the better approach might be
+to work on that, and widen your horizon a bit. You are welcome.
+
+## Controller Support
+
+systemd supports a number of controllers (but not all). Specifically, supported
+are:
+
+* on cgroupsv1: `cpu`, `cpuacct`, `blkio`, `memory`, `devices`, `pids`
+* on cgroupsv2: `cpu`, `io`, `memory`, `pids`
+
+It is our intention to natively support all cgroupsv2 controllers that might
+come up sooner or later. However, regarding cgroupsv1: at this point we will
+not add support for any other controllers anymore. This means systemd currently
+does not and will never manage the following controllers on cgroupsv1:
+`freezer`, `cpuset`, `net_cls`, `perf_event`, `net_prio`, `hugetlb`. Why not?
+Depending on the case, either their API semantics or implementations aren't
+really usable, or it's very clear they have no future on cgroupsv2, and we
+won't add new code for stuff that clearly has no future.
+
+Effectively this means that all those mentioned cgroupsv1 controllers are up
+for grabs: systemd won't manage them, and hence won't delegate them to your
+code (however, systemd will still mount their hierarchies, simply because it
+mounts all controller hierarchies it finds available in the kernel). If you
+decide to use them, then that's fine, but systemd won't help you with it (but
+also not interfere with it). To be nice to other tenants it might be wise to
+replicate the cgroup hierarchies of the other controllers in them too however,
+but of course that's between you and those other tenants, and systemd won't
+care. Replicating the cgroup hierarchies in those unsupported controllers would
+mean replicating the full cgroup paths in them, and hence the prefixing
+`.slice` components too, otherwise the hierarchies will start being orthogonal
+after all, and that's not really desirable. On more thing: systemd will clean
+up after you in the hierarchies it manages: if your daemon goes down, its
+cgroups will be removed too. You basically get the guarantee that you start
+with a pristine cgroup sub-tree for your service or scope whenever it is
+started. This is not the case however in the hierarchies systemd doesn't
+manage. This means that your programs should be ready to deal with left-over
+cgroups in them — from previous runs, and be extra careful with them as they
+might still carry settings that might not be valid anymore.
+
+Note a particular asymmetry here: if your systemd version doesn't support a
+specific controller on cgroupsv1 you can still make use of it for delegation,
+by directly fiddling with its hierarchy and replicating the cgroup tree there
+as necessary (as suggested above). However, on cgroupsv2 this is different:
+separately mounted hierarchies are not available, and delegation has always to
+happen through systemd itself. This means: when you update your kernel and it
+adds a new, so far unseen controller, and you want to use it for delegation,
+then you also need to update systemd to a version that groks it.
+
+## systemd as Container Payload
+
+systemd can happily run as a container payload's PID 1. Note that systemd
+unconditionally needs write access to the cgroup tree however, hence you need
+to delegate a sub-tree to it. Note that there's nothing too special you have to
+do beyond that: just invoke systemd as PID 1 inside the root of the delegated
+cgroup sub-tree, and it will figure out the rest: it will determine the cgroup
+it is running in and take possession of it. It won't interfere with any cgroup
+outside of the sub-tree it was invoked in. Use of `CLONE_NEWCGROUP` is hence
+optional (but of course wise).
+
+Note one particular asymmetry here though: systemd will try to take possession
+of the root cgroup you pass to it *in* *full*, i.e. it will not only
+create/remove child cgroups below it it will also attempt to manage the
+attributes of it. OTOH as mentioned above, when delegating a cgroup tree to
+somebody else it only passes the rights to create/remove sub-cgroups, but will
+insist on managing the delegated cgroup tree's top-level attributes. Or in
+other words: systemd is *greedy* when accepting delegated cgroup trees and also
+*greedy* when delegating them to others: it insists on managing attributes on
+the specific cgroup in both cases. A container manager that is itself a payload
+of a host systemd which wants to run a systemd as its own container payload
+instead hence needs to insert an extra level in the hierarchy in between, so
+that the systemd on the host and the one in the container won't fight for the
+attributes. That said, you likely should do that anyway, due to the
+no-processes-in-inner-cgroups rule, see below.
+
+When systemd runs as container payload it will make use of all hierarchies it
+has write access to. For legacy mode you need to make at least
+`/sys/fs/cgroup/systemd/` available, all other hierarchies are optional. For
+hybrid mode you need to add `/sys/fs/cgroup/unified/`. Finally, for fully
+unified you (of course, I guess) need to provide only `/sys/fs/cgroup/` itself.
+
+## Some Dos
+
+1. ⚡ If you go for implementation option 1a or 1b (as in the list above), then
+ each of your containers will have its own systemd-managed unit and hence
+ cgroup with possibly further sub-cgroups below. Typically the first process
+ running in that unit will be some kind of executor program, which will in
+ turn fork off the payload processes of the container. In this case don't
+ forget that there are two levels of delegation involved: first, systemd
+ delegates a group sub-tree to your executor. And then your executor should
+ delegate a sub-tree further down to the container payload. Oh, and because
+ of the no-process-in-inner-nodes rule, your executor needs to migrate itself
+ to a sub-cgroup of the cgroup it got delegated, too. Most likely you hence
+ want a two-pronged approach: below the cgroup you got started in, you want
+ one cgroup maybe called `supervisor/` where your manager runs in and then
+ for each container a sibling cgroup of that maybe called `payload-xyz/`.
+
+2. ⚡ Don't forget that the cgroups you create have to have names that are
+ suitable as UNIX file names, and that they live in the same namespace as the
+ various kernel attribute files. Hence, when you want to allow the user
+ arbitrary naming, you might need to escape some of the names (for example,
+ you really don't want to create a cgroup named `tasks`, just because the
+ user created a container by that name, because `tasks` after all is a magic
+ attribute in cgroupsv1, and your `mkdir()` will hence fail with `EEXIST`. In
+ systemd we do escaping by prefixing names that might collide with a kernel
+ attribute name with an underscore. You might want to do the same, but this
+ is really up to you how you do it. Just do it, and be careful.
+
+## Some Don'ts
+
+1. 🚫 Never create your own cgroups below arbitrary cgroups systemd manages, i.e
+ cgroups you haven't set `Delegate=` in. Specifically: 🔥 don't create your
+ own cgroups below the root cgroup 🔥. That's owned by systemd, and you will
+ step on systemd's toes if you ignore that, and systemd will step on
+ yours. Get your own delegated sub-tree, you may create as many cgroups there
+ as you like. Seriously, if you create cgroups directly in the cgroup root,
+ then all you do is ask for trouble.
+
+2. 🚫 Don't attempt to set `Delegate=` in slice units, and in particular not in
+ `-.slice`. It's not supported, and will generate an error.
+
+3. 🚫 Never *write* to any of the attributes of a cgroup systemd created for
+ you. It's systemd's private property. You are welcome to manipulate the
+ attributes of cgroups you created in your own delegated sub-tree, but the
+ cgroup tree of systemd itself is out of limits for you. It's fine to *read*
+ from any attribute you like however. That's totally OK and welcome.
+
+4. 🚫 When not using `CLONE_NEWCGROUP` when delegating a sub-tree to a container
+ payload running systemd, then don't get the idea that you can bind mount
+ only a sub-tree of the host's cgroup tree into the container. Part of the
+ cgroup API is that `/proc/$PID/cgroup` reports the cgroup path of every
+ process, and hence any path below `/sys/fs/cgroup/` needs to match what
+ `/proc/$PID/cgroup` of the payload processes reports. What you can do safely
+ however, is mount the upper parts of the cgroup tree read-only or even
+ replace it with an intermediary `tmpfs`, as long as the path to the
+ delegated sub-tree remains accessible as-is.
+
+5. ⚡ Think twice before delegating cgroupsv1 controllers to less privileged
+ containers. It's not safe, you basically allow your containers to freeze the
+ system with that and worse. Delegation is a strongpoint of cgroupsv2 though,
+ and there it's safe to treat delegation boundaries as privilege boundaries.
+
+And that's it for now. If you have further questions, refer to the systemd
+mailing list.
+
+— Berlin, 2018-04-20
diff --git a/doc/UIDS-GIDS.md b/doc/UIDS-GIDS.md
index e19cc88162..c380bbe140 100644
--- a/doc/UIDS-GIDS.md
+++ b/doc/UIDS-GIDS.md
@@ -241,3 +241,38 @@ really unused. It just means that these ranges have no well-established
pre-defined purposes between Linux, generic low-level distributions and
`systemd`. There might very well be other packages that allocate from these
ranges.
+
+## Notes on resolvability of user and group names
+
+User names, UIDs, group names and GIDs don't have to be resolvable using NSS
+(i.e. getpwuid() and getpwnam() and friends) all the time. However, systemd
+makes the following requirements:
+
+System users generally have to be resolvable during early boot already. This
+means they should not be provided by any networked service (as those usually
+become available during late boot only), except if a local cache is kept that
+makes them available during early boot too (i.e. before networking is
+up). Specifically, system users need to be resolvable at least before
+`systemd-udevd.service` and `systemd-tmpfiles.service` are started, as both
+need to resolve system users — but note that there might be more services
+requiring full resolvability of system users than just these two.
+
+Regular users do not need to be resolvable during early boot, it is sufficient
+if they become resolvable during late boot. Specifically, regular users need to
+be resolvable at the point in time the `nss-user-lookup.target` unit is
+reached. This target unit is generally used as synchronization point between
+providers of the user database and consumers of it. Services that require that
+the user database is fully available (for example, the login service
+`systemd-logind.service`) are ordered *after* it, while services that provide
+parts of the user database (for example an LDAP user database client) are
+ordered *before* it. Note that `nss-user-lookup.target` is a *passive* unit: in
+order to minimize synchronization points on systems that don't need it the unit
+is pulled into the initial transaction only if there's at least one service
+that really needs it, and that means only if there's a service providing the
+local user database somehow through IPC or suchlike. Or in other words: if you
+hack on some networked user database project, then make sure you order your
+service `Before=nss-user-lookup.target` and that you pull it in with
+`Wants=nss-user-lookup.target`. However, if you hack on some project that needs
+the user database to be up in full, then order your service
+`After=nss-user-lookup.target`, but do *not* pull it in via a `Wants=`
+dependency.
diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb
index e8e650cde6..532a1cc59c 100644
--- a/hwdb/60-evdev.hwdb
+++ b/hwdb/60-evdev.hwdb
@@ -461,6 +461,13 @@ evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnTOSHIBA:pnTECRAM11*
EVDEV_ABS_00=90:962:11
EVDEV_ABS_01=51:681:14
+# Toshiba Satellite R830
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnTOSHIBA:pnSATELLITER830*
+ EVDEV_ABS_00=1238:5785:53
+ EVDEV_ABS_01=1045:4826:76
+ EVDEV_ABS_35=1238:5785:53
+ EVDEV_ABS_36=1045:4826:76
+
#########################################
# Razer
#########################################
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 808ed54a77..2e24c86663 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -264,7 +264,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*
KEYBOARD_KEY_85=brightnessdown # Fn+Down Brightness Down
KEYBOARD_KEY_86=brightnessup # Fn+Up Brightness Up
KEYBOARD_KEY_87=battery # Fn+F3 battery icon
- KEYBOARD_KEY_88=unknown # Fn+F2 Turn On/Off Wireless - handled in hardware
+ KEYBOARD_KEY_88=!wlan # Fn+(F2|PrtScr|Home) Turn On/Off Wireless
KEYBOARD_KEY_89=ejectclosecd # Fn+F10 Eject CD
KEYBOARD_KEY_8a=suspend # Fn+F1 hibernate
KEYBOARD_KEY_8b=switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle")
@@ -326,6 +326,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*E7*:pvr*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr*
KEYBOARD_KEY_8c=!unknown
+# Dell XPS L702x
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDellInc.:pnDellSystemXPSL702X:pvr*
+ KEYBOARD_KEY_84=prog1
+ KEYBOARD_KEY_85=prog2
+
# Dell XPS12 9Q33
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr*
KEYBOARD_KEY_88=wlan
diff --git a/hwdb/60-sensor.hwdb b/hwdb/60-sensor.hwdb
index 8385efd28d..d7204422bc 100644
--- a/hwdb/60-sensor.hwdb
+++ b/hwdb/60-sensor.hwdb
@@ -193,6 +193,12 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnJumper:pnEZpad:*:rvr.A006:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, 1
#########################################
+# Kazam
+#########################################
+sensor:modalias:acpi:KIOX000A*:dmi:bvnINSYDECorp.:bvrVISION.I22K*:svnKAZAM:pnVISION:*
+ ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+
+#########################################
# Lamina
#########################################
sensor:modalias:acpi:SMO8500*:dmi:*svnLamina*:*pnT701BR.SE*
diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml
index 3e28fc6bee..f14b9aa250 100644
--- a/man/file-hierarchy.xml
+++ b/man/file-hierarchy.xml
@@ -53,16 +53,16 @@
<title>Description</title>
<para>Operating systems using the
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- system and service manager are organized based on a file system
- hierarchy inspired by UNIX, more specifically the hierarchy
- described in the <ulink
- url="http://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html">File
- System Hierarchy</ulink> specification and
- <citerefentry project='man-pages'><refentrytitle>hier</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
- This manual page describes a more minimal, modernized subset of
- these specifications that defines more strictly the suggestions
- and restrictions systemd makes on the file system
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> system and service
+ manager are organized based on a file system hierarchy inspired by UNIX, more specifically the hierarchy described
+ in the <ulink url="http://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html">File System Hierarchy</ulink>
+ specification and <citerefentry
+ project='man-pages'><refentrytitle>hier</refentrytitle><manvolnum>7</manvolnum></citerefentry>, with various
+ extensions, partially documented in the <ulink
+ url="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG Base Directory
+ Specification</ulink> and <ulink url="https://www.freedesktop.org/wiki/Software/xdg-user-dirs/">XDG User
+ Directories</ulink>. This manual page describes a more generalized, though minimal and modernized subset of these
+ specifications that defines more strictly the suggestions and restrictions systemd makes on the file system
hierarchy.</para>
<para>Many of the paths described here can be queried
@@ -87,7 +87,7 @@
<term><filename>/boot</filename></term>
<listitem><para>The boot partition used for bringing up the
system. On EFI systems, this is possibly the EFI System
- Partition, also see
+ Partition (ESP), also see
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
This directory is usually strictly local to the host, and
should be considered read-only, except when a new kernel or
@@ -97,6 +97,15 @@
</varlistentry>
<varlistentry>
+ <term><filename>/efi/</filename></term>
+ <listitem><para>If the boot partition <filename>/boot/</filename> is maintained separately from the EFI System
+ Partition (ESP), the latter is mounted here. Tools that need to operate on the EFI system partition should look
+ for it at this mount point first, and fall back to <filename>/boot/</filename> — if the former doesn't qualify
+ (for example if it is not a mount point or does not have the correct file system type
+ <constant>MSDOS_SUPER_MAGIC</constant>).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><filename>/etc</filename></term>
<listitem><para>System-specific configuration. This directory
may or may not be read-only. Frequently, this directory is
diff --git a/man/loginctl.xml b/man/loginctl.xml
index 65c5227ed3..3863ec6621 100644
--- a/man/loginctl.xml
+++ b/man/loginctl.xml
@@ -98,11 +98,9 @@
<varlistentry>
<term><option>--value</option></term>
- <listitem>
- <para>When printing properties with <command>show</command>,
- only print the value, and skip the property name and
- <literal>=</literal>.</para>
- </listitem>
+ <listitem><para>When showing session/user/seat properties,
+ only print the value, and skip the property name and
+ <literal>=</literal>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/os-release.xml b/man/os-release.xml
index 973e19747d..59db374411 100644
--- a/man/os-release.xml
+++ b/man/os-release.xml
@@ -74,7 +74,8 @@
shell style. All strings should be in UTF-8 format, and
non-printable characters should not be used. It is not supported
to concatenate multiple individually quoted strings. Lines
- beginning with "#" shall be ignored as comments.</para>
+ beginning with "#" shall be ignored as comments. Blank lines are
+ permitted and ignored.</para>
<para>The file <filename>/etc/os-release</filename> takes
precedence over <filename>/usr/lib/os-release</filename>.
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index 68ebf02f2e..67b6c4fd32 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -98,8 +98,7 @@
<row>
<entry><varname>kvm</varname></entry>
- <entry>Linux KVM kernel virtual machine, with whatever software, except
- Oracle Virtualbox</entry>
+ <entry>Linux KVM kernel virtual machine, with whatever software, except Oracle Virtualbox</entry>
</row>
<row>
@@ -119,8 +118,7 @@
<row>
<entry><varname>oracle</varname></entry>
- <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems),
- for legacy and KVM hypervisor</entry>
+ <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems), for legacy and KVM hypervisor</entry>
</row>
<row>
diff --git a/man/systemd-escape.xml b/man/systemd-escape.xml
index 513e9a6a97..98cedef77d 100644
--- a/man/systemd-escape.xml
+++ b/man/systemd-escape.xml
@@ -122,6 +122,7 @@
<varlistentry>
<term><option>--unescape</option></term>
+ <term><option>-u</option></term>
<listitem><para>Instead of escaping the specified strings,
undo the escaping, reversing the operation. May not be used in
@@ -132,6 +133,7 @@
<varlistentry>
<term><option>--mangle</option></term>
+ <term><option>-m</option></term>
<listitem><para>Like <option>--escape</option>, but only
escape characters that are obviously not escaped yet, and
diff --git a/man/systemd-journal-upload.xml b/man/systemd-journal-upload.xml
index a43062a6d5..fecffd5d9b 100644
--- a/man/systemd-journal-upload.xml
+++ b/man/systemd-journal-upload.xml
@@ -268,10 +268,10 @@ echo 0001 &gt;serial
SERVER=server
CLIENT=client
-openssl req -newkey rsa:1024 -nodes -out $SERVER.csr -keyout $SERVER.key -subj "/CN=$SERVER/"
+openssl req -newkey rsa:2048 -nodes -out $SERVER.csr -keyout $SERVER.key -subj "/CN=$SERVER/"
openssl ca -batch -config ca.conf -notext -in $SERVER.csr -out $SERVER.pem
-openssl req -newkey rsa:1024 -nodes -out $CLIENT.csr -keyout $CLIENT.key -subj "/CN=$CLIENT/"
+openssl req -newkey rsa:2048 -nodes -out $CLIENT.csr -keyout $CLIENT.key -subj "/CN=$CLIENT/"
openssl ca -batch -config ca.conf -notext -in $CLIENT.csr -out $CLIENT.pem
</programlisting>
diff --git a/man/systemd-networkd-wait-online.service.xml b/man/systemd-networkd-wait-online.service.xml
index 96715cad2f..7cec7da9d7 100644
--- a/man/systemd-networkd-wait-online.service.xml
+++ b/man/systemd-networkd-wait-online.service.xml
@@ -26,7 +26,7 @@
<refentry id="systemd-networkd-wait-online.service" conditional='ENABLE_NETWORKD'>
<refentryinfo>
- <title>systemd-networkd.service</title>
+ <title>systemd-networkd-wait-online.service</title>
<productname>systemd</productname>
<authorgroup>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index c1867b4ed2..f1bbfb94a2 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1987,7 +1987,9 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
<listitem><para>Variables read from files specified via <varname>EnvironmentFile=</varname> in the unit file</para></listitem>
- <listitem><para>Variables set by any PAM modules in case <varname>PAMName=</varname> is in effect, cf. <citerefentry project='man-pages'><refentrytitle>pam_env</refentrytitle><manvolnum>8</manvolnum></citerefentry></para></listitem>
+ <listitem><para>Variables set by any PAM modules in case <varname>PAMName=</varname> is in effect,
+ cf. <citerefentry
+ project='man-pages'><refentrytitle>pam_env</refentrytitle><manvolnum>8</manvolnum></citerefentry></para></listitem>
</itemizedlist>
<para>If the same environment variables are set by multiple of these sources, the later source — according to the
@@ -1995,7 +1997,8 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
<varname>UnsetEnvironment=</varname> are removed again from the compiled environment variable list, immediately
before it is passed to the executed process.</para>
- <para>The following select environment variables are set by the service manager itself for each invoked process:</para>
+ <para>The following select environment variables are set or propagated by the service manager for each invoked
+ process:</para>
<variablelist class='environment-variables'>
<varlistentry>
@@ -2046,24 +2049,11 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
<varlistentry>
<term><varname>$XDG_RUNTIME_DIR</varname></term>
- <listitem><para>The directory for volatile state. Set for the
- user <command>systemd</command> instance, and also in user
- sessions. See
- <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- </para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><varname>$XDG_SESSION_ID</varname></term>
- <term><varname>$XDG_SEAT</varname></term>
- <term><varname>$XDG_VTNR</varname></term>
-
- <listitem><para>The identifier of the session, the seat name,
- and virtual terminal of the session. Set by
- <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- for login sessions. <varname>$XDG_SEAT</varname> and
- <varname>$XDG_VTNR</varname> will only be set when attached to
- a seat and a tty.</para></listitem>
+ <listitem><para>The directory to use for runtime objects (such as IPC objects) and volatile state. Set for all
+ services run by the user <command>systemd</command> instance, as well as any system services that use
+ <varname>PAMName=</varname> with a PAM stack that includes <command>pam_systemd</command>. See below and
+ <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry> for more
+ information.</para></listitem>
</varlistentry>
<varlistentry>
@@ -2317,6 +2307,11 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
</listitem>
</varlistentry>
</variablelist>
+
+ <para>For system services, when <varname>PAMName=</varname> is enabled and <command>pam_systemd</command> is part
+ of the selected PAM stack, additional environment variables defined by systemd may be set for
+ services. Specifically, these are <varname>$XDG_SEAT</varname>, <varname>$XDG_VTNR</varname>, see
+ <citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry> for details.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index 4f29a24c27..5bb279333c 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -458,6 +458,10 @@
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>
@@ -849,11 +853,6 @@
information. Also see
<filename>network-online.target</filename> described
above.</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>$network</literal> facility.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -869,31 +868,24 @@
<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 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>
+ <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 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. Note that system users are always
- resolvable, and hence do not require any special ordering
- against this target.</para>
+ <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>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 8365cddc42..0c11119707 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -1555,28 +1555,28 @@
</row>
<row>
<entry><literal>%N</literal></entry>
- <entry>Unescaped full unit name</entry>
- <entry>Same as <literal>%n</literal>, but with escaping undone. This undoes the escaping used when generating unit names from arbitrary strings (see above). </entry>
+ <entry>Full unit name</entry>
+ <entry>Same as <literal>%n</literal>, but with the type suffix removed.</entry>
</row>
<row>
<entry><literal>%p</literal></entry>
<entry>Prefix name</entry>
- <entry>For instantiated units, this refers to the string before the <literal>@</literal> character of the unit name. For non-instantiated units, this refers to the name of the unit with the type suffix removed.</entry>
+ <entry>For instantiated units, this refers to the string before the first <literal>@</literal> character of the unit name. For non-instantiated units, same as <literal>%N</literal>.</entry>
</row>
<row>
<entry><literal>%P</literal></entry>
<entry>Unescaped prefix name</entry>
- <entry>Same as <literal>%p</literal>, but with escaping undone</entry>
+ <entry>Same as <literal>%p</literal>, but with escaping undone.</entry>
</row>
<row>
<entry><literal>%i</literal></entry>
<entry>Instance name</entry>
- <entry>For instantiated units: this is the string between the <literal>@</literal> character and the suffix of the unit name.</entry>
+ <entry>For instantiated units this is the string between the first <literal>@</literal> character and the type suffix. Empty for non-instantiated units.</entry>
</row>
<row>
<entry><literal>%I</literal></entry>
<entry>Unescaped instance name</entry>
- <entry>Same as <literal>%i</literal>, but with escaping undone</entry>
+ <entry>Same as <literal>%i</literal>, but with escaping undone.</entry>
</row>
<row>
<entry><literal>%f</literal></entry>
diff --git a/man/udevadm.xml b/man/udevadm.xml
index 1495f556f3..6bb54c86d8 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -131,9 +131,9 @@
<filename><optional>/sys</optional>/class/block/sda</filename>.
Note that this option usually is not very useful, since
<command>udev</command> can guess the type of the
- argument, so <command>udevadm
- --devpath=/class/block/sda</command> is equivalent to
- <command>udevadm /sys/class/block/sda</command>.</para>
+ argument, so <command>udevadm info
+ --path=/class/block/sda</command> is equivalent to
+ <command>udevadm info /sys/class/block/sda</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -144,8 +144,8 @@
e.g. <filename><optional>/dev</optional>/sda</filename>.
Note that this option usually is not very useful, since
<command>udev</command> can guess the type of the
- argument, so <command>udevadm --name=sda</command> is
- equivalent to <command>udevadm /dev/sda</command>.</para>
+ argument, so <command>udevadm info --name=sda</command> is
+ equivalent to <command>udevadm info /dev/sda</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/meson.build b/meson.build
index 358b41b9d1..a2dc4040df 100644
--- a/meson.build
+++ b/meson.build
@@ -387,8 +387,7 @@ if cc.get_id() == 'clang'
foreach arg : ['-Wno-typedef-redefinition',
'-Wno-gnu-variable-sized-type-not-at-end',
]
- if cc.has_argument(arg,
- name : '@0@ is supported'.format(arg))
+ if cc.has_argument(arg)
add_project_arguments(arg, language : 'c')
endif
endforeach
@@ -429,8 +428,7 @@ endforeach
if get_option('buildtype') != 'debug'
foreach arg : ['-ffunction-sections',
'-fdata-sections']
- if cc.has_argument(arg,
- name : '@0@ is supported'.format(arg))
+ if cc.has_argument(arg)
add_project_arguments(arg, language : 'c')
endif
endforeach
diff --git a/src/activate/activate.c b/src/activate/activate.c
index c856c8c100..e605d50ce0 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -201,7 +201,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
r = rearrange_stdio(start_fd, start_fd, STDERR_FILENO); /* invalidates start_fd on success + error */
if (r < 0)
- return log_error_errno(errno, "Failed to move fd to stdin+stdout: %m");
+ return log_error_errno(r, "Failed to move fd to stdin+stdout: %m");
} else {
if (start_fd != SD_LISTEN_FDS_START) {
diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c
index 6a93c9109c..1e897cb982 100644
--- a/src/basic/audit-util.c
+++ b/src/basic/audit-util.c
@@ -95,10 +95,9 @@ bool use_audit(void) {
fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
if (fd < 0) {
cached_use = !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT, EPERM);
- if (errno == EPERM)
- log_debug_errno(errno, "Audit access prohibited, won't talk to audit");
- }
- else {
+ if (!cached_use)
+ log_debug_errno(errno, "Won't talk to audit: %m");
+ } else {
cached_use = true;
safe_close(fd);
}
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 3d30497f74..0db8292e70 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -1703,7 +1703,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
if (r == -ENOTTY && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
/* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
if (mkdir(new_path, 0755) < 0)
- return r;
+ return -errno;
plain_directory = true;
} else if (r < 0)
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index c0962f288f..296da2898b 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2598,8 +2598,10 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
}
r = write_string_stream(f, s, 0);
- if (r < 0)
+ if (r < 0) {
log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
+ clearerr(f);
+ }
}
}
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 678ab12bb8..6d7875361c 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -361,14 +361,21 @@ bool fdname_is_valid(const char *s) {
}
int fd_get_path(int fd, char **ret) {
- char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ _cleanup_close_ int dir = -1;
+ char fdname[DECIMAL_STR_MAX(int)];
int r;
- xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+ dir = open("/proc/self/fd/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+ if (dir < 0)
+ /* /proc is not available or not set up properly, we're most likely
+ * in some chroot environment. */
+ return errno == ENOENT ? -EOPNOTSUPP : -errno;
- r = readlink_malloc(procfs_path, ret);
+ xsprintf(fdname, "%i", fd);
- if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */
+ r = readlinkat_malloc(dir, fdname, ret);
+ if (r == -ENOENT)
+ /* If the file doesn't exist the fd is invalid */
return -EBADF;
return r;
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 29b941348a..9875abff51 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -63,6 +63,7 @@ int write_string_stream_ts(
struct timespec *ts) {
bool needs_nl;
+ int r;
assert(f);
assert(line);
@@ -87,6 +88,13 @@ int write_string_stream_ts(
if (fputc('\n', f) == EOF)
return -errno;
+ if (flags & WRITE_STRING_FILE_SYNC)
+ r = fflush_sync_and_check(f);
+ else
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+
if (ts) {
struct timespec twice[2] = {*ts, *ts};
@@ -94,10 +102,7 @@ int write_string_stream_ts(
return -errno;
}
- if (flags & WRITE_STRING_FILE_SYNC)
- return fflush_sync_and_check(f);
- else
- return fflush_and_check(f);
+ return 0;
}
static int write_string_file_atomic(
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 85c8070a1b..c65ba4bfe5 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -978,8 +978,19 @@ int fsync_directory_of_file(int fd) {
return r;
r = fd_get_path(fd, &path);
- if (r < 0)
+ if (r < 0) {
+ log_debug("Failed to query /proc/self/fd/%d%s: %m",
+ fd,
+ r == -EOPNOTSUPP ? ", ignoring" : "");
+
+ if (r == -EOPNOTSUPP)
+ /* If /proc is not available, we're most likely running in some
+ * chroot environment, and syncing the directory is not very
+ * important in that case. Let's just silently do nothing. */
+ return 0;
+
return r;
+ }
if (!path_is_absolute(path))
return -EINVAL;
diff --git a/src/basic/log.c b/src/basic/log.c
index 16a2431c54..9a39da7c16 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -699,9 +699,8 @@ int log_internalv_realm(
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
return -error;
- /* Make sure that %m maps to the specified error */
- if (error != 0)
- errno = error;
+ /* Make sure that %m maps to the specified error (or "Success"). */
+ errno = error;
(void) vsnprintf(buffer, sizeof buffer, format, ap);
@@ -749,9 +748,8 @@ static int log_object_internalv(
if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
return -error;
- /* Make sure that %m maps to the specified error */
- if (error != 0)
- errno = error;
+ /* Make sure that %m maps to the specified error (or "Success"). */
+ errno = error;
/* Prepend the object name before the message */
if (object) {
@@ -874,8 +872,7 @@ int log_format_iovec(
* since vasprintf() leaves it afterwards at
* an undefined location */
- if (error != 0)
- errno = error;
+ errno = error;
va_copy(aq, ap);
r = vasprintf(&m, format, aq);
@@ -976,8 +973,7 @@ int log_struct_internal(
while (format) {
va_list aq;
- if (error != 0)
- errno = error;
+ errno = error;
va_copy(aq, ap);
(void) vsnprintf(buf, sizeof buf, format, aq);
@@ -1275,8 +1271,7 @@ int log_syntax_internal(
if (log_target == LOG_TARGET_NULL)
return -error;
- if (error != 0)
- errno = error;
+ errno = error;
va_start(ap, format);
(void) vsnprintf(buffer, sizeof buffer, format, ap);
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
index 34b8956a12..86422ced72 100644
--- a/src/basic/missing_syscall.h
+++ b/src/basic/missing_syscall.h
@@ -416,8 +416,14 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
#if !HAVE_STATX
# ifndef __NR_statx
-# if defined __i386__
+# if defined __aarch64__ || defined __arm__
+# define __NR_statx 397
+# elif defined __alpha__
+# define __NR_statx 522
+# elif defined __i386__ || defined __powerpc64__
# define __NR_statx 383
+# elif defined __sparc__
+# define __NR_statx 360
# elif defined __x86_64__
# define __NR_statx 332
# else
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 39b4a98d89..971701acca 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -332,13 +332,16 @@ int detect_vm(void) {
/* We have to use the correct order here:
*
- * -> First try to detect Oracle Virtualbox, even if it uses KVM.
- * -> Second try to detect from cpuid, this will report KVM for
- * whatever software is used even if info in dmi is overwritten.
- * -> Third try to detect from dmi. */
+ * → First, try to detect Oracle Virtualbox, even if it uses KVM, as well as Xen even if it cloaks as Microsoft
+ * Hyper-V.
+ *
+ * → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is
+ * overwritten.
+ *
+ * → Third, try to detect from DMI. */
dmi = detect_vm_dmi();
- if (dmi == VIRTUALIZATION_ORACLE) {
+ if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN)) {
r = dmi;
goto finish;
}
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 992a3ba4c2..2751b8da4f 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -50,12 +50,17 @@ stub_sources = '''
if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
efi_cc = get_option('efi-cc')
efi_ld = get_option('efi-ld')
-
efi_incdir = get_option('efi-includedir')
- have_header = (gnu_efi_arch != '' and
- cc.has_header('@0@/@1@/efibind.h'.format(efi_incdir, gnu_efi_arch)))
- if have_header and EFI_MACHINE_TYPE_NAME == ''
+ gnu_efi_path_arch = ''
+ foreach name : [gnu_efi_arch, EFI_MACHINE_TYPE_NAME]
+ if (gnu_efi_path_arch == '' and name != '' and
+ cc.has_header('@0@/@1@/efibind.h'.format(efi_incdir, name)))
+ gnu_efi_path_arch = name
+ endif
+ endforeach
+
+ if gnu_efi_path_arch != '' and EFI_MACHINE_TYPE_NAME == ''
error('gnu-efi is available, but EFI_MACHINE_TYPE_NAME is unknown')
endif
@@ -68,7 +73,7 @@ if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
endif
endif
- have_gnu_efi = have_header and efi_libdir != ''
+ have_gnu_efi = gnu_efi_path_arch != '' and efi_libdir != ''
else
have_gnu_efi = false
endif
@@ -91,7 +96,7 @@ if have_gnu_efi
objcopy = find_program('objcopy')
efi_ldsdir = get_option('efi-ldsdir')
- arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_arch)
+ arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch)
if efi_ldsdir == ''
efi_ldsdir = join_paths(efi_libdir, 'gnuefi')
cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds))
@@ -121,7 +126,7 @@ if have_gnu_efi
'-Wsign-compare',
'-Wno-missing-field-initializers',
'-isystem', efi_incdir,
- '-isystem', join_paths(efi_incdir, gnu_efi_arch),
+ '-isystem', join_paths(efi_incdir, gnu_efi_path_arch),
'-include', efi_config_h]
if efi_arch == 'x86_64'
compile_args += ['-mno-red-zone',
@@ -141,7 +146,7 @@ if have_gnu_efi
'-nostdlib',
'-znocombreloc',
'-L', efi_libdir,
- join_paths(efi_ldsdir, 'crt0-efi-@0@.o'.format(gnu_efi_arch))]
+ join_paths(efi_ldsdir, 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))]
if efi_arch == 'aarch64' or efi_arch == 'arm'
# Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary'
# instead, and add required symbols manually.
diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c
index 48666f64a2..deebafbf47 100644
--- a/src/core/bpf-firewall.c
+++ b/src/core/bpf-firewall.c
@@ -705,13 +705,14 @@ int bpf_firewall_supported(void) {
1,
BPF_F_NO_PREALLOC);
if (fd < 0) {
- log_debug_errno(r, "Can't allocate BPF LPM TRIE map, BPF firewalling is not supported: %m");
+ log_debug_errno(fd, "Can't allocate BPF LPM TRIE map, BPF firewalling is not supported: %m");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
safe_close(fd);
- if (bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &program) < 0) {
+ r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &program);
+ if (r < 0) {
log_debug_errno(r, "Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m");
return supported = BPF_FIREWALL_UNSUPPORTED;
}
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index f480664613..489112087f 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -32,6 +32,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "path-util.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
@@ -351,13 +352,13 @@ static int bus_cgroup_set_transient_property(
if (streq(name, "Delegate")) {
int b;
- if (!UNIT_VTABLE(u)->can_delegate)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
-
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
+ if (!UNIT_VTABLE(u)->can_delegate && b)
+ log_unit_notice(u, "Delegate=yes set, but has no effect for unit type");
+
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->delegate = b;
c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0;
@@ -370,9 +371,6 @@ static int bus_cgroup_set_transient_property(
} else if (streq(name, "DelegateControllers")) {
CGroupMask mask = 0;
- if (!UNIT_VTABLE(u)->can_delegate)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
-
r = sd_bus_message_enter_container(message, 'a', "s");
if (r < 0)
return r;
@@ -389,7 +387,7 @@ static int bus_cgroup_set_transient_property(
cc = cgroup_controller_from_string(t);
if (cc < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup contoller '%s'", t);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown cgroup controller '%s'", t);
mask |= CGROUP_CONTROLLER_TO_MASK(cc);
}
@@ -414,6 +412,9 @@ static int bus_cgroup_set_transient_property(
unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
}
+ if (!UNIT_VTABLE(u)->can_delegate && c->delegate)
+ log_unit_notice(u, "Delegate=yes set, but has no effect for unit type");
+
return 1;
}
diff --git a/src/core/device.c b/src/core/device.c
index b0dd469fd1..a57c34ddf1 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -769,8 +769,8 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (revents != EPOLLIN) {
static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
- if (!ratelimit_test(&limit))
- log_error_errno(errno, "Failed to get udev event: %m");
+ if (ratelimit_test(&limit))
+ log_warning("Failed to get udev event");
if (!(revents & EPOLLIN))
return 0;
}
diff --git a/src/core/execute.c b/src/core/execute.c
index 7292b815db..2f4b70ab3b 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2311,14 +2311,7 @@ static int apply_mount_namespace(
_cleanup_strv_free_ char **empty_directories = NULL;
char *tmp = NULL, *var = NULL;
const char *root_dir = NULL, *root_image = NULL;
- NamespaceInfo ns_info = {
- .ignore_protect_paths = false,
- .private_dev = context->private_devices,
- .protect_control_groups = context->protect_control_groups,
- .protect_kernel_tunables = context->protect_kernel_tunables,
- .protect_kernel_modules = context->protect_kernel_modules,
- .mount_apivfs = context->mount_apivfs,
- };
+ NamespaceInfo ns_info = {};
bool needs_sandboxing;
BindMount *bind_mounts = NULL;
unsigned n_bind_mounts = 0;
@@ -2358,6 +2351,16 @@ static int apply_mount_namespace(
needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
+ if (needs_sandboxing)
+ ns_info = (NamespaceInfo) {
+ .ignore_protect_paths = false,
+ .private_dev = context->private_devices,
+ .protect_control_groups = context->protect_control_groups,
+ .protect_kernel_tunables = context->protect_kernel_tunables,
+ .protect_kernel_modules = context->protect_kernel_modules,
+ .mount_apivfs = context->mount_apivfs,
+ };
+
r = setup_namespace(root_dir, root_image,
&ns_info, context->read_write_paths,
needs_sandboxing ? context->read_only_paths : NULL,
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 9c27972aff..1ecf5c0d9f 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -22,6 +22,7 @@
#include <ftw.h>
#include <stdlib.h>
#include <sys/mount.h>
+#include <sys/statvfs.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -387,6 +388,35 @@ static int nftw_cb(
return FTW_CONTINUE;
};
+
+static int relabel_cgroup_filesystems(void) {
+ int r;
+ struct statfs st;
+
+ r = cg_all_unified();
+ if (r == 0) {
+ /* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
+ only when the filesystem has been already populated by a previous instance of systemd
+ running from initrd. Otherwise don't remount anything and leave the filesystem read-write
+ for the cgroup filesystems to be mounted inside. */
+ r = statfs("/sys/fs/cgroup", &st);
+ if (r < 0) {
+ return log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup: %m");
+ }
+
+ if (st.f_flags & ST_RDONLY)
+ (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
+
+ label_fix("/sys/fs/cgroup", false, false);
+ nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+
+ if (st.f_flags & ST_RDONLY)
+ (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
+
+ return 0;
+}
#endif
int mount_setup(bool loaded_policy) {
@@ -411,15 +441,9 @@ int mount_setup(bool loaded_policy) {
nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- /* Temporarily remount the root cgroup filesystem to give it a proper label. */
- r = cg_all_unified();
- if (r == 0) {
- (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
- label_fix("/sys/fs/cgroup", false, false);
- nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
- } else if (r < 0)
- return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
+ r = relabel_cgroup_filesystems();
+ if (r < 0)
+ return r;
after_relabel = now(CLOCK_MONOTONIC);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 58c9a9de79..fec9c276fc 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -269,11 +269,11 @@ static void sync_with_progress(void) {
int main(int argc, char *argv[]) {
bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
- bool in_container, use_watchdog = false;
+ bool in_container, use_watchdog = false, can_initrd;
_cleanup_free_ char *cgroup = NULL;
char *arguments[3];
unsigned retries;
- int cmd, r;
+ int cmd, r, umount_log_level = LOG_INFO;
static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
char *watchdog_device;
@@ -349,6 +349,7 @@ int main(int argc, char *argv[]) {
need_swapoff = !in_container;
need_loop_detach = !in_container;
need_dm_detach = !in_container;
+ can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0;
/* Unmount all mountpoints, swaps, and loopback devices */
for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
@@ -366,7 +367,7 @@ int main(int argc, char *argv[]) {
if (need_umount) {
log_info("Unmounting file systems.");
- r = umount_all(&changed);
+ r = umount_all(&changed, umount_log_level);
if (r == 0) {
need_umount = false;
log_info("All filesystems unmounted.");
@@ -390,7 +391,7 @@ int main(int argc, char *argv[]) {
if (need_loop_detach) {
log_info("Detaching loop devices.");
- r = loopback_detach_all(&changed);
+ r = loopback_detach_all(&changed, umount_log_level);
if (r == 0) {
need_loop_detach = false;
log_info("All loop devices detached.");
@@ -402,7 +403,7 @@ int main(int argc, char *argv[]) {
if (need_dm_detach) {
log_info("Detaching DM devices.");
- r = dm_detach_all(&changed);
+ r = dm_detach_all(&changed, umount_log_level);
if (r == 0) {
need_dm_detach = false;
log_info("All DM devices detached.");
@@ -419,6 +420,16 @@ int main(int argc, char *argv[]) {
goto initrd_jump;
}
+ if (!changed && umount_log_level == LOG_INFO && !can_initrd) {
+ /* There are things we cannot get rid of. Loop one more time
+ * with LOG_ERR to inform the user. Note that we don't need
+ * to do this if there is a initrd to switch to, because that
+ * one is likely to get rid of the remounting mounts. If not,
+ * it will log about them. */
+ umount_log_level = LOG_ERR;
+ continue;
+ }
+
/* If in this iteration we didn't manage to
* unmount/deactivate anything, we simply give up */
if (!changed) {
@@ -450,8 +461,7 @@ int main(int argc, char *argv[]) {
arguments[2] = NULL;
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
- if (!in_container && !in_initrd() &&
- access("/run/initramfs/shutdown", X_OK) == 0) {
+ if (can_initrd) {
r = switch_root_initramfs();
if (r >= 0) {
argv[0] = (char*) "/shutdown";
diff --git a/src/core/umount.c b/src/core/umount.c
index de826edd4d..ab2d4ffa62 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -48,8 +48,9 @@
typedef struct MountPoint {
char *path;
- char *options;
- char *type;
+ char *remount_options;
+ unsigned long remount_flags;
+ bool try_remount_ro;
dev_t devnum;
LIST_FIELDS(struct MountPoint, mount_point);
} MountPoint;
@@ -61,8 +62,7 @@ static void mount_point_free(MountPoint **head, MountPoint *m) {
LIST_REMOVE(mount_point, *head, m);
free(m->path);
- free(m->options);
- free(m->type);
+ free(m->remount_options);
free(m);
}
@@ -85,8 +85,7 @@ static int mount_points_list_get(MountPoint **head) {
return -errno;
for (i = 1;; i++) {
- _cleanup_free_ char *path = NULL, *options = NULL, *type = NULL;
- char *p = NULL;
+ _cleanup_free_ char *path = NULL, *options = NULL, *flags = NULL, *type = NULL, *p = NULL;
MountPoint *m;
int k;
@@ -96,15 +95,15 @@ static int mount_points_list_get(MountPoint **head) {
"%*s " /* (3) major:minor */
"%*s " /* (4) root */
"%ms " /* (5) mount point */
- "%*s" /* (6) mount flags */
+ "%ms" /* (6) mount flags */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
"%ms " /* (9) file system type */
"%*s" /* (10) mount source */
"%ms" /* (11) mount options */
"%*[^\n]", /* some rubbish at the end */
- &path, &type, &options);
- if (k != 3) {
+ &path, &flags, &type, &options);
+ if (k != 4) {
if (k == EOF)
break;
@@ -127,22 +126,53 @@ static int mount_points_list_get(MountPoint **head) {
mount_point_ignore(p) ||
path_startswith(p, "/dev") ||
path_startswith(p, "/sys") ||
- path_startswith(p, "/proc")) {
- free(p);
+ path_startswith(p, "/proc"))
continue;
- }
m = new0(MountPoint, 1);
- if (!m) {
- free(p);
+ if (!m)
return -ENOMEM;
- }
- m->path = p;
- m->options = options;
- options = NULL;
- m->type = type;
- type = NULL;
+ free_and_replace(m->path, p);
+
+ /* If we are in a container, don't attempt to
+ * read-only mount anything as that brings no real
+ * benefits, but might confuse the host, as we remount
+ * the superblock here, not the bind mount.
+ *
+ * If the filesystem is a network fs, also skip the
+ * remount. It brings no value (we cannot leave
+ * a "dirty fs") and could hang if the network is down.
+ * Note that umount2() is more careful and will not
+ * hang because of the network being down. */
+ m->try_remount_ro = detect_container() <= 0 &&
+ !fstype_is_network(type) &&
+ !fstype_is_api_vfs(type) &&
+ !fstype_is_ro(type) &&
+ !fstab_test_yes_no_option(options, "ro\0rw\0");
+
+ if (m->try_remount_ro) {
+ _cleanup_free_ char *unknown_flags = NULL;
+
+ /* mount(2) states that mount flags and options need to be exactly the same
+ * as they were when the filesystem was mounted, except for the desired
+ * changes. So we reconstruct both here and adjust them for the later
+ * remount call too. */
+
+ r = mount_option_mangle(flags, 0, &m->remount_flags, &unknown_flags);
+ if (r < 0)
+ return r;
+ if (!isempty(unknown_flags))
+ log_warning("Ignoring unknown mount flags '%s'.", unknown_flags);
+
+ r = mount_option_mangle(options, m->remount_flags, &m->remount_flags, &m->remount_options);
+ if (r < 0)
+ return r;
+
+ /* MS_BIND is special. If it is provided it will only make the mount-point
+ * read-only. If left out, the super block itself is remounted, which we want. */
+ m->remount_flags = (m->remount_flags|MS_REMOUNT|MS_RDONLY) & ~MS_BIND;
+ }
LIST_PREPEND(mount_point, *head, m);
}
@@ -333,6 +363,8 @@ static int delete_loopback(const char *device) {
_cleanup_close_ int fd = -1;
int r;
+ assert(device);
+
fd = open(device, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return errno == ENOENT ? 0 : -errno;
@@ -382,12 +414,14 @@ static bool nonunmountable_path(const char *path) {
|| path_startswith(path, "/run/initramfs");
}
-static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
+static int remount_with_timeout(MountPoint *m, int umount_log_level) {
pid_t pid;
int r;
BLOCK_SIGNALS(SIGCHLD);
+ assert(m);
+
/* Due to the possiblity of a remount operation hanging, we
* fork a child process and set a timeout. If the timeout
* lapses, the assumption is that that particular remount
@@ -396,12 +430,12 @@ static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
if (r < 0)
return r;
if (r == 0) {
- log_info("Remounting '%s' read-only in with options '%s'.", m->path, options);
+ log_info("Remounting '%s' read-only in with options '%s'.", m->path, m->remount_options);
/* Start the mount operation here in the child */
- r = mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
+ r = mount(NULL, m->path, NULL, m->remount_flags, m->remount_options);
if (r < 0)
- log_error_errno(errno, "Failed to remount '%s' read-only: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Failed to remount '%s' read-only: %m", m->path);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
@@ -411,19 +445,21 @@ static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
log_error_errno(r, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
(void) kill(pid, SIGKILL);
} else if (r == -EPROTO)
- log_error_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
+ log_debug_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
else if (r < 0)
log_error_errno(r, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
return r;
}
-static int umount_with_timeout(MountPoint *m, bool *changed) {
+static int umount_with_timeout(MountPoint *m, int umount_log_level) {
pid_t pid;
int r;
BLOCK_SIGNALS(SIGCHLD);
+ assert(m);
+
/* Due to the possiblity of a umount operation hanging, we
* fork a child process and set a timeout. If the timeout
* lapses, the assumption is that that particular umount
@@ -443,7 +479,7 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
* then return EBUSY).*/
r = umount2(m->path, MNT_FORCE);
if (r < 0)
- log_error_errno(errno, "Failed to unmount %s: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Failed to unmount %s: %m", m->path);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
@@ -453,7 +489,7 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
log_error_errno(r, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
(void) kill(pid, SIGKILL);
} else if (r == -EPROTO)
- log_error_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
+ log_debug_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
else if (r < 0)
log_error_errno(r, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
@@ -462,38 +498,15 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
/* This includes remounting readonly, which changes the kernel mount options.
* Therefore the list passed to this function is invalidated, and should not be reused. */
-
-static int mount_points_list_umount(MountPoint **head, bool *changed) {
+static int mount_points_list_umount(MountPoint **head, bool *changed, int umount_log_level) {
MountPoint *m;
int n_failed = 0;
assert(head);
+ assert(changed);
LIST_FOREACH(mount_point, m, *head) {
- bool mount_is_readonly;
-
- mount_is_readonly = fstab_test_yes_no_option(m->options, "ro\0rw\0");
-
- /* If we are in a container, don't attempt to
- read-only mount anything as that brings no real
- benefits, but might confuse the host, as we remount
- the superblock here, not the bind mount.
- If the filesystem is a network fs, also skip the
- remount. It brings no value (we cannot leave
- a "dirty fs") and could hang if the network is down.
- Note that umount2() is more careful and will not
- hang because of the network being down. */
- if (detect_container() <= 0 &&
- !fstype_is_network(m->type) &&
- !mount_is_readonly) {
- _cleanup_free_ char *options = NULL;
- /* MS_REMOUNT requires that the data parameter
- * should be the same from the original mount
- * except for the desired changes. Since we want
- * to remount read-only, we should filter out
- * rw (and ro too, because it confuses the kernel) */
- (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
-
+ if (m->try_remount_ro) {
/* We always try to remount directories
* read-only first, before we go on and umount
* them.
@@ -508,16 +521,19 @@ static int mount_points_list_umount(MountPoint **head, bool *changed) {
* somehwere else via a bind mount. If we
* explicitly remount the super block of that
* alias read-only we hence should be
- * relatively safe regarding keeping dirty an fs
+ * relatively safe regarding keeping a dirty fs
* we cannot otherwise see.
*
* Since the remount can hang in the instance of
* remote filesystems, we remount asynchronously
- * and skip the subsequent umount if it fails */
- if (remount_with_timeout(m, options, &n_failed) < 0) {
- if (nonunmountable_path(m->path))
+ * and skip the subsequent umount if it fails. */
+ if (remount_with_timeout(m, umount_log_level) < 0) {
+ /* Remount failed, but try unmounting anyway,
+ * unless this is a mount point we want to skip. */
+ if (nonunmountable_path(m->path)) {
n_failed++;
- continue;
+ continue;
+ }
}
}
@@ -528,12 +544,10 @@ static int mount_points_list_umount(MountPoint **head, bool *changed) {
continue;
/* Trying to umount */
- if (umount_with_timeout(m, changed) < 0)
+ if (umount_with_timeout(m, umount_log_level) < 0)
n_failed++;
- else {
- if (changed)
- *changed = true;
- }
+ else
+ *changed = true;
}
return n_failed;
@@ -544,13 +558,12 @@ static int swap_points_list_off(MountPoint **head, bool *changed) {
int n_failed = 0;
assert(head);
+ assert(changed);
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
log_info("Deactivating swap %s.", m->path);
if (swapoff(m->path) == 0) {
- if (changed)
- *changed = true;
-
+ *changed = true;
mount_point_free(head, m);
} else {
log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
@@ -561,12 +574,13 @@ static int swap_points_list_off(MountPoint **head, bool *changed) {
return n_failed;
}
-static int loopback_points_list_detach(MountPoint **head, bool *changed) {
+static int loopback_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
MountPoint *m, *n;
int n_failed = 0, k;
struct stat root_st;
assert(head);
+ assert(changed);
k = lstat("/", &root_st);
@@ -585,12 +599,12 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
log_info("Detaching loopback %s.", m->path);
r = delete_loopback(m->path);
if (r >= 0) {
- if (r > 0 && changed)
+ if (r > 0)
*changed = true;
mount_point_free(head, m);
} else {
- log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Could not detach loopback %s: %m", m->path);
n_failed++;
}
}
@@ -598,12 +612,13 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
return n_failed;
}
-static int dm_points_list_detach(MountPoint **head, bool *changed) {
+static int dm_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
MountPoint *m, *n;
int n_failed = 0, r;
dev_t rootdev;
assert(head);
+ assert(changed);
r = get_block_device("/", &rootdev);
if (r <= 0)
@@ -611,21 +626,18 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) {
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
- if (major(rootdev) != 0)
- if (rootdev == m->devnum) {
- n_failed ++;
- continue;
- }
+ if (major(rootdev) != 0 && rootdev == m->devnum) {
+ n_failed ++;
+ continue;
+ }
log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
r = delete_dm(m->devnum);
if (r >= 0) {
- if (changed)
- *changed = true;
-
+ *changed = true;
mount_point_free(head, m);
} else {
- log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
+ log_full_errno(umount_log_level, errno, "Could not detach DM %s: %m", m->path);
n_failed++;
}
}
@@ -633,16 +645,18 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) {
return n_failed;
}
-static int umount_all_once(bool *changed) {
+static int umount_all_once(bool *changed, int umount_log_level) {
int r;
LIST_HEAD(MountPoint, mp_list_head);
+ assert(changed);
+
LIST_HEAD_INIT(mp_list_head);
r = mount_points_list_get(&mp_list_head);
if (r < 0)
goto end;
- r = mount_points_list_umount(&mp_list_head, changed);
+ r = mount_points_list_umount(&mp_list_head, changed, umount_log_level);
end:
mount_points_list_free(&mp_list_head);
@@ -650,17 +664,19 @@ static int umount_all_once(bool *changed) {
return r;
}
-int umount_all(bool *changed) {
+int umount_all(bool *changed, int umount_log_level) {
bool umount_changed;
int r;
+ assert(changed);
+
/* Retry umount, until nothing can be umounted anymore. Mounts are
* processed in order, newest first. The retries are needed when
* an old mount has been moved, to a path inside a newer mount. */
do {
umount_changed = false;
- r = umount_all_once(&umount_changed);
+ r = umount_all_once(&umount_changed, umount_log_level);
if (umount_changed)
*changed = true;
} while (umount_changed);
@@ -672,6 +688,8 @@ int swapoff_all(bool *changed) {
int r;
LIST_HEAD(MountPoint, swap_list_head);
+ assert(changed);
+
LIST_HEAD_INIT(swap_list_head);
r = swap_list_get(&swap_list_head);
@@ -686,17 +704,19 @@ int swapoff_all(bool *changed) {
return r;
}
-int loopback_detach_all(bool *changed) {
+int loopback_detach_all(bool *changed, int umount_log_level) {
int r;
LIST_HEAD(MountPoint, loopback_list_head);
+ assert(changed);
+
LIST_HEAD_INIT(loopback_list_head);
r = loopback_list_get(&loopback_list_head);
if (r < 0)
goto end;
- r = loopback_points_list_detach(&loopback_list_head, changed);
+ r = loopback_points_list_detach(&loopback_list_head, changed, umount_log_level);
end:
mount_points_list_free(&loopback_list_head);
@@ -704,17 +724,19 @@ int loopback_detach_all(bool *changed) {
return r;
}
-int dm_detach_all(bool *changed) {
+int dm_detach_all(bool *changed, int umount_log_level) {
int r;
LIST_HEAD(MountPoint, dm_list_head);
+ assert(changed);
+
LIST_HEAD_INIT(dm_list_head);
r = dm_list_get(&dm_list_head);
if (r < 0)
goto end;
- r = dm_points_list_detach(&dm_list_head, changed);
+ r = dm_points_list_detach(&dm_list_head, changed, umount_log_level);
end:
mount_points_list_free(&dm_list_head);
diff --git a/src/core/umount.h b/src/core/umount.h
index 7c029c384c..a6613e6ad6 100644
--- a/src/core/umount.h
+++ b/src/core/umount.h
@@ -20,10 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int umount_all(bool *changed);
+int umount_all(bool *changed, int umount_log_level);
int swapoff_all(bool *changed);
-int loopback_detach_all(bool *changed);
+int loopback_detach_all(bool *changed, int umount_log_level);
-int dm_detach_all(bool *changed);
+int dm_detach_all(bool *changed, int umount_log_level);
diff --git a/src/import/import.c b/src/import/import.c
index 454e64e3cb..b94b196b87 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -208,7 +208,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
fd = STDIN_FILENO;
(void) readlink_malloc("/proc/self/fd/0", &pretty);
- log_info("Importing '%s', saving as '%s'.", pretty, local);
+ log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
}
r = sd_event_default(&event);
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 07cb257151..4a85d751bc 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2197,7 +2197,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
cancelled = m->scheduled_shutdown_type != NULL;
reset_scheduled_shutdown(m);
- if (cancelled) {
+ if (cancelled && m->enable_wall_messages) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *tty = NULL;
uid_t uid = 0;
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 93648e1be0..fa054fcfc3 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -238,7 +238,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h
assert(link);
assert(callback);
- if (link->flags & IFF_UP) {
+ if (link->flags & IFF_UP && netdev->kind == NETDEV_KIND_BOND) {
log_netdev_debug(netdev, "Link '%s' was up when attempting to enslave it. Bringing link down.", link->ifname);
r = link_down(link);
if (r < 0)
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index ecb96cdb57..aaea2ae908 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -332,6 +332,11 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
link_set_dhcp_routes(link);
+ if (link->dhcp4_messages == 0) {
+ link->dhcp4_configured = true;
+ link_check_ready(link);
+ }
+
return 1;
}
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 234e0a4602..f82e915399 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -202,11 +202,13 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
if (r < 0)
return r;
+ route->family = AF_INET6;
+
while (n < n_prefixes) {
route_update(route, &prefix, pd_prefix_len, NULL, NULL,
0, 0, RTN_UNREACHABLE);
- r = route_configure(route, link, NULL);
+ r = route_configure(route, dhcp6_link, NULL);
if (r < 0) {
route_free(route);
return r;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 64c45080df..31d3f7ade7 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -2985,7 +2985,7 @@ network_file_fail:
goto dhcp4_address_fail;
}
- r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
+ r = sd_dhcp_client_new(&link->dhcp_client, link->network ? link->network->dhcp_anonymize : 0);
if (r < 0)
return log_link_error_errno(link, r, "Failed to create DHCPv4 client: %m");
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 70dca5219b..8446feb316 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -379,14 +379,12 @@ void route_update(Route *route,
unsigned char type) {
assert(route);
- assert(src);
- assert(gw);
- assert(prefsrc);
+ assert(src || src_prefixlen == 0);
- route->src = *src;
+ route->src = src ? *src : (union in_addr_union) {};
route->src_prefixlen = src_prefixlen;
- route->gw = *gw;
- route->prefsrc = *prefsrc;
+ route->gw = gw ? *gw : (union in_addr_union) {};
+ route->prefsrc = prefsrc ? *prefsrc : (union in_addr_union) {};
route->scope = scope;
route->protocol = protocol;
route->type = type;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 54b2137c9c..e58d318c76 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -1989,6 +1989,8 @@ int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_ar
if (q < 0 && r == 0)
r = q;
+ errno = 0; /* Reset errno explicitly, so that log_debug_errno() will properly print 'Success'
+ * for q == 0, instead of whatever is set in errno */
log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
}
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 15cfe4e4f7..33340b1f20 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -409,6 +409,27 @@ int config_parse(const char *unit,
continuation = mfree(continuation);
}
+ if (continuation) {
+ r = parse_line(unit,
+ filename,
+ ++line,
+ sections,
+ lookup,
+ table,
+ flags,
+ &section,
+ &section_line,
+ &section_ignored,
+ continuation,
+ userdata);
+ if (r < 0) {
+ if (flags & CONFIG_PARSE_WARN)
+ log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
+ return r;
+
+ }
+ }
+
return 0;
}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 6ae97cf107..3666be61ec 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4063,8 +4063,9 @@ static void print_status_info(
char ** dropin;
STRV_FOREACH(dropin, i->dropin_paths) {
- if (! dir || last) {
- printf(dir ? " " : " Drop-In: ");
+ if (!dir || last) {
+ printf(dir ? " " :
+ " Drop-In: ");
dir = mfree(dir);
@@ -4074,7 +4075,8 @@ static void print_status_info(
return;
}
- printf("%s\n %s", dir,
+ printf("%s\n"
+ " %s", dir,
special_glyph(TREE_RIGHT));
}
@@ -8374,6 +8376,7 @@ static int talk_initctl(void) {
_cleanup_close_ int fd = -1;
char rl;
int r;
+ const char *p;
rl = action_to_runlevel();
if (!rl)
@@ -8381,17 +8384,21 @@ static int talk_initctl(void) {
request.runlevel = rl;
- fd = open(INIT_FIFO, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+ FOREACH_STRING(p, "/run/initctl", "/dev/initctl") {
+ fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+ if (fd >= 0 || errno != ENOENT)
+ break;
+ }
if (fd < 0) {
if (errno == ENOENT)
return 0;
- return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
+ return log_error_errno(errno, "Failed to open initctl fifo: %m");
}
r = loop_write(fd, &request, sizeof(request), false);
if (r < 0)
- return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
+ return log_error_errno(r, "Failed to write to %s: %m", p);
return 1;
#else
diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h
index f6fb40fbb5..425e38e2e2 100644
--- a/src/systemd/sd-bus-vtable.h
+++ b/src/systemd/sd-bus-vtable.h
@@ -157,8 +157,7 @@ struct sd_bus_vtable {
{ \
.type = _SD_BUS_VTABLE_END, \
.flags = 0, \
- .x = { \
- }, \
+ .x = { { 0 } }, \
}
_SD_END_DECLARATIONS;
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index 72c53ab6a0..028bf5ef3b 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -291,6 +291,11 @@ static const char* const config_file[] = {
"3\n",
"[Section]\n"
+ "setting1=1\\\n" /* continuation with extra trailing backslash at the end */
+ "2\\\n"
+ "3\\\n",
+
+ "[Section]\n"
"setting1=1\\\\\\\n" /* continuation with trailing escape symbols */
"\\\\2\n", /* note that C requires one level of escaping, so the
* parser gets "…1 BS BS BS NL BS BS 2 NL", which
@@ -307,6 +312,11 @@ static const char* const config_file[] = {
"foobar",
"[Section]\n"
+ "setting1=" /* a line above LINE_MAX length, with continuation */
+ x1000("ABCD") "\\\n" /* and an extra trailing backslash */
+ "foobar\\\n",
+
+ "[Section]\n"
"setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */
x1000(x1000("x") x10("abcde")) "\n",
@@ -359,27 +369,27 @@ static void test_config_parse(unsigned i, const char *s) {
assert_se(streq(setting1, "1"));
break;
- case 4:
+ case 4 ... 5:
assert_se(r == 0);
assert_se(streq(setting1, "1 2 3"));
break;
- case 5:
+ case 6:
assert_se(r == 0);
assert_se(streq(setting1, "1\\\\ \\\\2"));
break;
- case 6:
+ case 7:
assert_se(r == 0);
assert_se(streq(setting1, x1000("ABCD")));
break;
- case 7:
+ case 8 ... 9:
assert_se(r == 0);
assert_se(streq(setting1, x1000("ABCD") " foobar"));
break;
- case 8 ... 9:
+ case 10 ... 11:
assert_se(r == -ENOBUFS);
assert_se(setting1 == NULL);
break;
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index cbacfae66b..608cfbb58f 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -879,6 +879,9 @@ static int path_set_perms(Item *i, const char *path) {
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+ if (i->type == EMPTY_DIRECTORY && !S_ISDIR(st.st_mode))
+ return log_error_errno(EEXIST, "'%s' already exists and is not a directory. ", path);
+
return fd_set_perms(i, fd, &st);
}
@@ -1591,7 +1594,7 @@ static int create_item(Item *i) {
_fallthrough_;
case EMPTY_DIRECTORY:
- r = path_set_perms(i, i->path);
+ r = glob_item(i, path_set_perms);
if (q < 0)
return q;
if (r < 0)
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
index 9bdaef8d90..8179a5e2f8 100644
--- a/src/udev/net/ethtool-util.c
+++ b/src/udev/net/ethtool-util.c
@@ -418,7 +418,7 @@ static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_uset
if (!u)
return -ENOMEM;
- ecmd.req = u->base;
+ u->base = ecmd.req;
offset = 0;
memcpy(u->link_modes.supported, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in
index df9396d895..e940c7c9ad 100644
--- a/units/systemd-binfmt.service.in
+++ b/units/systemd-binfmt.service.in
@@ -10,7 +10,8 @@
[Unit]
Description=Set Up Additional Binary Formats
Documentation=man:systemd-binfmt.service(8) man:binfmt.d(5)
-Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt
+Documentation=https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html
+Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
DefaultDependencies=no
Conflicts=shutdown.target
After=proc-sys-fs-binfmt_misc.automount
diff --git a/units/systemd-initctl.service.in b/units/systemd-initctl.service.in
index 6cfed3da11..2b4b957dce 100644
--- a/units/systemd-initctl.service.in
+++ b/units/systemd-initctl.service.in
@@ -8,7 +8,7 @@
# (at your option) any later version.
[Unit]
-Description=/dev/initctl Compatibility Daemon
+Description=initctl Compatibility Daemon
Documentation=man:systemd-initctl.service(8)
DefaultDependencies=no
diff --git a/units/systemd-initctl.socket b/units/systemd-initctl.socket
index 61f877ba7d..9d97579908 100644
--- a/units/systemd-initctl.socket
+++ b/units/systemd-initctl.socket
@@ -8,12 +8,12 @@
# (at your option) any later version.
[Unit]
-Description=/dev/initctl Compatibility Named Pipe
+Description=initctl Compatibility Named Pipe
Documentation=man:systemd-initctl.service(8)
DefaultDependencies=no
Before=sockets.target
[Socket]
-ListenFIFO=/run/systemd/initctl/fifo
+ListenFIFO=/run/initctl
Symlinks=/dev/initctl
SocketMode=0600