1
0
mirror of https://github.com/systemd/systemd synced 2026-03-17 18:44:46 +01:00

Compare commits

..

No commits in common. "5f94ac543529cd118b5091b9b567400a2ae4444c" and "51df483846219c86e1e6c405f295a6b873084e0e" have entirely different histories.

8 changed files with 94 additions and 573 deletions

366
NEWS
View File

@ -1,371 +1,5 @@
systemd System and Service Manager systemd System and Service Manager
CHANGES WITH 249 in spe:
* When operating on disk images via the --image= switch of various
tools (such as systemd-nspawn or systemd-dissect), and multiple
suitable root or /usr/ partitions exist in the image, then a simple
strverscmp() inspired comparison is done on the GPT partition label,
and the newest partition picked. This permits a simple and generic
whole-file-system A/B update logic where new operating system
versions are dropped into partitions whose label is then updated with
a matching version identifier.
* systemd-sysusers now supports querying the passwords to set for the
users it creates via the "credentials" logic introduced in v247: the
passwd.hashed-password.<user> and passwd.plaintext-password.<user>
credentials are consulted for the password to use (either in UNIX
hashed form, or literally). By default these credentials are inherited
down from PID1 (which in turn imports it from a container manager if
there is one). This permits easy configuration of user passwords
during first boot. Example:
# systemd-nspawn -i foo.raw --volatile=yes --set-credential=passwd.plaintext-password.root:foo
Note that systemd-sysusers operates in purely additive mode: it
executes no operation if the declared users already exist, and hence
doesn't set any passwords as effect of the command line above if the
specified root user exists already in the image. (Note that
--volatile=yes ensures it doesn't, though.)
* systemd-firstboot now also supports querying various system
parameters via the credential subsystems. Thus, as above this may be
used to initialize important system parameters on first boot of
previously unprovisioned images (i.e. images with a mostly empty
/etc/).
* The systemd-ask-password now also supports reading passwords from the
credentials subsystem, via the new --credential= switch.
* Services gained a new ExitType= setting which can configure how to
determine when a service exited: the default is "main" which defines
the runtime by the service's main process lifetime (this matches the
only behaviour implemented in v248 and before), but with "cgroup" the
runtime is defined by the existence of any process in the service's
cgroup.
* The systemd-machine-id-setup tool now supports a --image= switch for
provisioning a machine ID file into an OS disk image, similar to how
--root= operates on an OS file tree. This matches the existing switch
of the same name to the systemd-tmpfiles, systemd-firstboot or
systemd-sysusers tools.
* Similar, systemd-repart gained support for a --image= switch, too. In
combination with the existing --size= makes the tool particularly
useful for easily growing disk images in a single command invocation,
following the declarative rules included in the image itself.
* systemd-repart's partition configuration files gained support for a
new switch MakeDirectories= which may be used to create arbitrary
directories inside file systems that are created, before registering
them in the partition table. This is useful in particular if root
partitions are created that way to create mount point directories for
other partitions included in the image. For example, a disk image
that is created to contain a /home/ and a /var/ partition in addition
to a root partition may MakeDirectories= to create /home/ and /var/
as empty directories in the root file system on creation so that the
resulting image can mounted immediately, even in read-only mode.
* systemd-repart's CopyBlocks= setting gained support for a special
value "auto". If used a suitable, matching partition on the booted OS
is found as source to copy blocks from. This is useful for
implementing replicating installers, that are booted from one medium
and then stream their own root partition on the target medium.
* systemd-repart's partition configuration files gained support for a
Flags= and a ReadOnly= setting, allowing control of the GPT partition
flags for the created partitions: this is useful for marking newly
created partitions as read-only from the start.
* The /etc/os-release file has been extended with two new (optional)
variables IMAGE_VERSION= and IMAGE_ID=, for carrying identification
and versioning information for OS images that are updated
consistently, comprehensively and atomically as one image. The two
new specifiers %M, %A now resolve to these two fields in the various
configuration options that resolve specifiers.
* portablectl gained a new switch --extension= for enabling portable
service images with extensions that follow the extension image
concept introduced with v248.
* systemd-coredump will now extract ELF build-id information from
processes dumping core and include it in the coredump
report. Moreover, if will look for ELF .note.package sections that
may carry distribution packaging meta-information about the crashing
process. This is useful to directly embed the RPM or Debian (or any
other) package name and version in the ELF files where they originate
from, making it easy to match up coredump reports with the software
versions they were found it. This is particular useful on
environments with ELF files form multiple vendors, different
distributions and versions, as it is common today, in particular in a
containerized and sand-boxed world. For further information, see:
https://systemd.io/COREDUMP_PACKAGE_METADATA
* A new udev hwdb has been added for Firewire audio devices
* sd-bus' sd_bus_is_ready() and sd_bus_is_open() calls now accept a
NULL bus object, for which they will return false. Or in other words,
an unallocated bus connection is neither ready nor open.
* The native Journal protocol has been documented. Clients may talk
this as alternative to the classic BSD syslog protocol for locally
delivering log records to the Journal. The protocol has been stable
since a long time and in fact been implemented already in a variety
of alternative client libraries. This documentation makes the support
for that official:
https://systemd.io/JOURNAL_NATIVE_PROTOCOL
* A new BPFProgram= setting has been added to service files. It may be
set to a path to a loaded kernel BPF program, i.e. a path to a bpffs
file, or a bind mount or symlink to one. This may be used to upload
and manage BPF programs externally and then hook arbitrary systemd
services into them.
* The "home.arpa" domain that has been officially declared as the
choice for domain for local home networks per RFC 8375 has been added
to the default NTA list of resolved, since DNSSEC is generally not
available on private domains.
* The CPUAffinity= setting of unit files now resolves "%" specifiers.
* A new ManageForeignRoutingPolicyRules= setting has been added to
.network files which may be used to exclude foreign-created routing
policy rules from systemd-networkd management.
* systemd-network-wait-online gained two new switches -4 and -6 that
may be used to tweak whether to wait for only IPv4 or only IPv6
connectivity.
* .network files gained a new RequiredFamilyForOnline= setting to
fine-tune whether to require an IPv4 or IPv6 address in order to
consider an interface "online".
* The RestrictAddressFamilies= setting in service files now supports a
new special value "none". If specified sockets of all address
families will be made unavailable to services configured that way.
* The DHCP server logic configured in .network files gained a new
setting RelayTarget= that turns the server into a DHCP server
relay. The RelayAgentCircuitId= and RelayAgentRemoteId= settings may
be used to further tweak the DHCP relay behaviour.
* The DHCP server logic also gained a new setting ServerAddress= in
.network files for explicitly specifying the server IP address to
use. If not used, the address is determined automatically, as before.
* The sd-device API acquired a new API function
sd_device_get_usec_initialized() that returns the monotonic timestamp
when a udev device appeared in the database first.
* systemd-fstab-generator and systemd-repart have been updated to
support booting from disks that carry only a /usr/ partition but no
root partition yet, but where systemd-repart can add them in on first
boot. This is useful for implementing systems that ship with a single
/usr/ file system and whose root file system shall be set up on a
LUKS encrypted volume whose key is generated locally (and possibly
enrolled in TPM), and which is set up and formatted during first
boot.
* The [Address] section of .network files now accepts a new
RouteMetric= setting that configures the routing metric to use for
the prefix route created as effect of the address
configuration. Similar, the [DHCPv6PrefixDelegation] and [IPv6Prefix]
sections gained matching settings for their prefix routes. (The
option of the same name of the [DHCPv6] section is moved to
[IPv6AcceptRA], since it conceptually belongs there; the old option
is still understood for compatibility.)
* The DHCPv6 IAID and DUID are now explicitly configurable in .network
files.
* A new udev property ID_NET_DHCP_BROADCAST on network interface
devices is not honoured by systemd-networkd, that controls whether to
issue DHCP offers via broadcasting. This is used to ensure that s390
layer 3 network interfaces work out-of-the-box with systemd-networkd.
* nss-myhostname and systemd-resolved will now synthesize address
records for a new special hostname "_outbound". The name will always
resolve to the local IP addresses most likely used for outbound
connections towards the default route. On multi-homed hosts this is
useful to have a stable handle referring to "the" local IP address
that matters most, to the point where this is defined.
* The Discoverable Partition Specification has been updated with a new
GPT partition flag defined its partition types: a "growfs"
flag. Whenever partitions with this flag set are automatically
mounted (i.e. via systemd-gpt-auto-generator or the --image= switch
of systemd-nspawn or other tools; and as opposed to explicit mounting
via /etc/fstab), the file system within the partition is
automatically grown to the full size of the partition should it be
smaller. If the file system size already matches the partition size
this flag has no effect. Previously, this functionality has been
available via the explicit x-systemd.growfs mount option, and this
new flag extends this to automatically discovered mounts. A new
GrowFileSystem= setting has been added to systemd-repart drop-in
files that allows configuring this partition flag. This new flag
defaults to on for partitions automatically created by
systemd-repart, except if they are marked read-only. See the
specification for further details:
https://systemd.io/DISCOVERABLE_PARTITIONS
* .network files gained a new setting RoutToNTP= in the [DHCPv4]
section. If enabled (which is the default), and an NTP server address
is acquired through a DHCP lease on this interface an explicit route
to this address is created on this interface to ensure that NTP
traffic to the NTP server acquired on an interface is also routed
trough that interface. The pre-existing RoutesToDNS= setting that
implements the same for DNS servers is now enabled by default.
* A pair of service settings SocketBindAllow= + SocketBindDeny= have
been added that may be used to restrict the network interfaces
sockets created by the service may be bound to. This is implemented
via BPF.
* A new ConditionFirmware= condition type has been added to unit
files. It may be used to detect certain firmware features. At the
moment it may check whether running on an UEFI system, a device.tree
system or if the system is compatible with some specified device-tree
feature.
* hostnamed gained a new Describe() D-Bus method that returns a JSON
serialization of the host data it exposes. This is exposed via
"hostnamectl --json=" to acquire a host identity description in
JSON. It's our intention to add a similar concept to most services
and objects systemd manages, in order to simplify integration with
program code the consumes JSON.
* Similar, networkd gained a Describe() method on its Manager and Link
bus objects. This is exposed via "networkctl --json=".
* hostnamectl's various set-xyz verbs (e.g. "hostnamectl set-hostname")
have been renamed to just xyz (e.g. "hostnamectl hostname") and may
now be used to print the indicated data in terse form, instead of
only setting it. The old names continue to be supported for
compatibility.
* systemd-detect-virt and ConditionVirtualization= are now able to
correctly identify Amazon EC2 environments.
* The LogLevelMax= setting of unit files now applies not only to log
messages generated *by* the service, but also to log messages
generated *about* the service by PID 1. To suppress logs concerning a
specific service comprehensively, set this option to a high log
level.
* bootctl gained support for a new --make-machine-id-directory= switch
that allows precise control on whether to create the top-level
per-machine directory in the boot partition that typically contain
Type #1 boot loader entries.
* During build SBAT data to include in the systemd-boot EFI PE binaries
may be specified now.
* /etc/crypttab learnt a new option "headless". If specified any
requests to query the user interactively for passwords or PINs will
be skipped. This is useful on systems that are headless, i.e. where
an interactive user is generally not present.
* FIDO2 support in systemd-cryptenroll/systemd-cryptsetup and
systemd-homed has been updated to allow explicit configuration of the
"user presence" and "user verification" checks, as well as whether a
PIN is required for authentication, via the new switches
--fido2-with-user-presence=, --fido2-with-user-verification=,
--fido2-with-client-pin= to systemd-cryptenroll and homectl. Which
features are available, and may be enabled or disabled depends on the
used FIDO2 token.
* systemd-nspawn's --private-user= switch now accepts the special value
"identity" which configures a user namespacing environment with an
identity mapping of 65535 UIDs. This means the container UID 0 is
mapped to the host UID 0, and the UID 1 to host UID 1. On first look
this doesn't appear to be useful, however it does reduce the attack
surface a bit, since the resulting container will possess process
capabilities only within its namespace and not on the host.
* systemd-nspawn's --private-user-chown switch has been replaced by a
more generic --private-user-ownership= switch that accepts one of
three values: "chown" is equivalent to the old --private-user-chown,
and "off" is equivalent to the absence of the old switch. The value
"map" uses the new UID mapping mounts of Linux 5.12 to map ownership
of files and directories of the underlying image to the chosen UID
range for the container. "auto" is equivalent to "map" if UID mapping
mount are supported, otherwise it is equivalent to "chown". The short
-U switch systemd-nspawn now implies --private-user-ownership=auto
instead of the old --private-user-chown. Effectively this means: if
the backing file system supports UID mapping mounts the feature is
now used by default if -U is used. Generally, it's a good idea to use
UID mapping mounts instead of recursive chown()ing, since it allows
running containers off immutable images (since no modifications of
the images need to take place), and share images between multiple
instances. Moreover, the recursive chown()ing operation is slow and
can be avoided. Conceptually it's also a good thing if transient UID
range uses do not leak into persistent file ownership anymore. TLDR:
finally, the last major drawback of user namespacing has been
removed, and -U should always be used (unless you use btrfs, where
UID mapped mounts do not exist; or your container actually needs
privileges on the host).
* nss-systemd now synthesizes user and group shadow records in addition
to the main user and group records. Thus, hashed passwords managed by
systemd-homed are now accessible via the shadow database.
* The userdb logic (and thus nss-systemd, and so on) now read
additional user/group definitions in JSON format from the drop-in
directories /etc/userdb/, /run/userdb/, /run/host/userdb/ and
/usr/lib/userdb/. This is a simple and powerful mechanism for making
additional users available to the system, with full integration into
NSS including the shadow databases. Since the full JSON user/group
record format is supported this may also be used to define users with
resource management settings and other runtime settings that
pam_systemd and systemd-logind enforce at login.
* The userdbctl tool gained two new switches --with-dropin= and
--with-varlink= which can be used to fine-tune the sources used for
user database lookups.
* systemd-nspawn gained a new switch --bind-user= for binding a host
user account into the container. This does three things: the user's
home directory is bind mounted from the host into the container,
below the /run/userdb/home/ hierarchy. A free UID is picked in the
container, and a user namespacing UID mapping to the host user's UID
installed. And finally, a minimal JSON user and group record (along
with its hashed password) is dropped into /run/host/userdb/. These
records are picked up automatically by the userdb drop-in logic
describe above, and allow the user to login with the same password as
on the host. Effectively this means: if host and container run new
enough systemd versions making a host user available to the container
is trivially simple.
* systemd-journal-gatewayd now supports the switches --user, --system,
--merge, --file= that are equivalent to the same switches of
journalctl, and permit exposing only the specified subset of the
Journal records.
* networkctl will now show an over-all "online" state in the per-link
information.
* In .network files a new OutgoingInterface= setting has been added to
specify the output interface in bridge FDB setups.
* In ,network files the Multipath group ID may now be configured for
[NextHop] entries, via the new Group= setting.
* The OnFailure= dependency between units is now augmented with a
implicit reverse dependency OnFailureOf= (this new dependency cannot
be configured directly it's only created as effect of an OnFailure=
dependency in the reverse order — it's visible in "systemctl show"
however). Similar, Slice= now has an reverse dependency SliceOf=,
that is also not configurable directly, but useful to determine all
units that are members of a slice.
* A pair of new dependency types between units PropagatesStopTo= +
StopPropagatedFrom= has been added, that allows propagation of unit
stop events between two units. It operates similar to the existing
PropagatesReloadTo= + ReloadPropagatedFrom= dependencies.
CHANGES WITH 248: CHANGES WITH 248:
* A concept of system extension images is introduced. Such images may * A concept of system extension images is introduced. Such images may

View File

@ -26,8 +26,6 @@ Information about build requirements is provided in the [README file](README).
Consult our [NEWS file](NEWS) for information about what's new in the most recent systemd versions. Consult our [NEWS file](NEWS) for information about what's new in the most recent systemd versions.
Please see the [Code Map](docs/ARCHITECTURE.md) for information about this repository's layout and content.
Please see the [Hacking guide](docs/HACKING.md) for information on how to hack on systemd and test your modifications. Please see the [Hacking guide](docs/HACKING.md) for information on how to hack on systemd and test your modifications.
Please see our [Contribution Guidelines](docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests. Please see our [Contribution Guidelines](docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.

View File

@ -1,121 +0,0 @@
---
title: systemd repository architecture
category: Contributing
layout: default
---
# Code Map
This section will attempt to provide a high-level overview of the various
components of the systemd repository.
# Source Code
Directories in `src/` provide the implementation of all daemons, libraries and
command-line tools shipped by the project. There are many, and more are
constantly added, so we will not enumerate them all here - the directory
names are self-explanatory.
## Shared Code
You might wonder what kind of common code belongs in `src/shared/` and what
belongs in `src/basic/`. The split is like this: anything that is used to
implement the public shared object we provide (sd-bus, sd-login, sd-id128,
nss-systemd, nss-mymachines, nss-resolve, nss-myhostname, pam_systemd), must
be located in `src/basic` (those objects are not allowed to link to
libsystemd-shared.so). Conversely, anything which is shared between multiple
components and does not need to be in `src/basic/`, should be in
`src/shared/`.
To summarize:
`src/basic/`
- may be used by all code in the tree
- may not use any code outside of `src/basic/`
`src/libsystemd/`
- may be used by all code in the tree, except for code in `src/basic/`
- may not use any code outside of `src/basic/`, `src/libsystemd/`
`src/shared/`
- may be used by all code in the tree, except for code in `src/basic/`,
`src/libsystemd/`, `src/nss-*`, `src/login/pam_systemd.*`, and files under
`src/journal/` that end up in `libjournal-client.a` convenience library.
- may not use any code outside of `src/basic/`, `src/libsystemd/`, `src/shared/`
## PID 1
Code located in `src/core/` implements the main logic of the systemd system (and user)
service manager.
BPF helpers written in C and used by PID 1 can be found under `src/core/bpf/`.
## UDEV
Sources for the udev daemon and command-line tool (single binary) can be found under
`src/udev/`.
## Unit Tests
Source files found under `src/test/` implement unit-level testing, mostly for
modules found in `src/basic/` and `src/shared/`, but not exclusively. Each test
file is compiled in a standalone binary that can be run to exercise the
corresponding module. While most of the tests can be ran by any user, some
require privileges, and will attempt to clearly log about what they need
(mostly in the form of effective capabilities). These tests are self-contained,
and generally safe to run on a host without side effects.
Ideally, every module in `src/basic/` and `src/shared/` should have a corresponding
unit test under `src/test/`, which exercises every helper function.
# Integration Tests
Sources in `test/` implement system-level testing for executables, libraries and
daemons that are shipped by the project. They require privileges to run, and
are not safe to execute directly on a host. By default they will build an image
and run the test under it via `QEMU` or `systemd-nspawn`.
Most of those tests should be able to run via `systemd-nspawn`, which is orders of
magnitude faster than `QEMU`, but some tests require privileged operations like
using `dm-crypt` or `loopdev`. They are clearly marked if that is the case.
See `test/README.testsuite` for more specific details.
# HWDB
Rules built in the static `HWDB` database shipped by the project can be found
under `hwdb.d/`. Some of these files are updated automatically, some are filled
by contributors.
# Documentation
## systemd.io
Markdown files found under `docs/` are automatically published on the
[systemd.io](https://systemd.io) website using Github Pages. A minimal unit test
to ensure the formatting doesn't have errors is included in the
`meson test -C build/ github-pages` run as part of the CI.
## MAN pages
Manpages for binaries and libraries, and the DBUS interfaces, can be found under
`man/` and should ideally be kept in sync with changes to the corresponding
binaries and libraries.
## Translations
Translations files for binaries and daemons, provided by volunteers, can be found
under `po/` in the usual format. They are kept up to date by contributors and by
automated tools.
# System Configuration files and presets
Presets (or templates from which they are generated) for various daemons and tools
can be found under various directories such as `factory/`, `modprobe.d/`, `network/`,
`presets/`, `rules.d/`, `shell-completion/`, `sysctl.d/`, `sysusers.d/`, `tmpfiles.d/`.
# Utilities for Developers
`tools/`, `coccinelle/`, `.github/`, `.semaphore/`, `.lgtm/`, `.mkosi/` host various
utilities and scripts that are used by maintainers and developers. They are not
shipped or installed.

View File

@ -135,6 +135,31 @@ layout: default
global in global variables, for example data parsed from command lines, see global in global variables, for example data parsed from command lines, see
below. below.
- You might wonder what kind of common code belongs in `src/shared/` and what
belongs in `src/basic/`. The split is like this: anything that is used to
implement the public shared object we provide (sd-bus, sd-login, sd-id128,
nss-systemd, nss-mymachines, nss-resolve, nss-myhostname, pam_systemd), must
be located in `src/basic` (those objects are not allowed to link to
libsystemd-shared.so). Conversely, anything which is shared between multiple
components and does not need to be in `src/basic/`, should be in
`src/shared/`.
To summarize:
`src/basic/`
- may be used by all code in the tree
- may not use any code outside of `src/basic/`
`src/libsystemd/`
- may be used by all code in the tree, except for code in `src/basic/`
- may not use any code outside of `src/basic/`, `src/libsystemd/`
`src/shared/`
- may be used by all code in the tree, except for code in `src/basic/`,
`src/libsystemd/`, `src/nss-*`, `src/login/pam_systemd.*`, and files under
`src/journal/` that end up in `libjournal-client.a` convenience library.
- may not use any code outside of `src/basic/`, `src/libsystemd/`, `src/shared/`
- Our focus is on the GNU libc (glibc), not any other libcs. If other libcs are - Our focus is on the GNU libc (glibc), not any other libcs. If other libcs are
incompatible with glibc it's on them. However, if there are equivalent POSIX incompatible with glibc it's on them. However, if there are equivalent POSIX
and Linux/GNU-specific APIs, we generally prefer the POSIX APIs. If there and Linux/GNU-specific APIs, we generally prefer the POSIX APIs. If there

View File

@ -1405,7 +1405,7 @@
<varlistentry> <varlistentry>
<term><varname>ConditionPathExists=</varname></term> <term><varname>ConditionPathExists=</varname></term>
<listitem><para>Check for the existence of a file. If the specified absolute path name does not exist, <listitem><para>Check for the exists of a file. If the specified absolute path name does not exist,
the condition will fail. If the absolute path name passed to the condition will fail. If the absolute path name passed to
<varname>ConditionPathExists=</varname> is prefixed with an exclamation mark <varname>ConditionPathExists=</varname> is prefixed with an exclamation mark
(<literal>!</literal>), the test is negated, and the unit is only started if the path does not (<literal>!</literal>), the test is negated, and the unit is only started if the path does not

View File

@ -3,8 +3,6 @@
#include <errno.h> #include <errno.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include "sd-messages.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "bus-error.h" #include "bus-error.h"
#include "dbus-device.h" #include "dbus-device.h"
@ -14,7 +12,6 @@
#include "log.h" #include "log.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h" #include "path-util.h"
#include "ratelimit.h"
#include "serialize.h" #include "serialize.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
@ -125,8 +122,8 @@ static int device_load(Unit *u) {
return r; return r;
if (!u->description) { if (!u->description) {
/* Generate a description based on the path, to be used until the device is initialized /* Generate a description based on the path, to be used until the
properly */ device is initialized properly */
r = unit_name_to_path(u->id, &u->description); r = unit_name_to_path(u->id, &u->description);
if (r < 0) if (r < 0)
log_unit_debug_errno(u, r, "Failed to unescape name: %m"); log_unit_debug_errno(u, r, "Failed to unescape name: %m");
@ -493,37 +490,15 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool
if (dev) { if (dev) {
r = sd_device_get_syspath(dev, &sysfs); r = sd_device_get_syspath(dev, &sysfs);
if (r < 0) if (r < 0) {
return log_device_debug_errno(dev, r, "Couldn't get syspath from device, ignoring: %m"); log_device_debug_errno(dev, r, "Couldn't get syspath from device, ignoring: %m");
return 0;
}
} }
r = unit_name_from_path(path, ".device", &e); r = unit_name_from_path(path, ".device", &e);
if (r < 0) { if (r < 0)
/* Let's complain about overly long device names only at most once every 5s or so. This is return log_device_error_errno(dev, r, "Failed to generate unit name from device path: %m");
* something we should mention, since relevant devices are not manageable by systemd, but not
* flood the log about. */
static RateLimit rate_limit = {
.interval = 5 * USEC_PER_SEC,
.burst = 1,
};
/* If we cannot convert a device name to a unit name then let's ignore the device. So far,
* devices with such long names weren't really the kind you want to manage with systemd
* anyway, hence this shouldn't be a problem. */
if (r == -ENAMETOOLONG)
return log_struct_errno(
ratelimit_below(&rate_limit) ? LOG_WARNING : LOG_DEBUG, r,
"MESSAGE_ID=" SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR,
"DEVICE=%s", path,
LOG_MESSAGE("Device path '%s' too long to fit into unit name, ignoring device.", path));
return log_struct_errno(
ratelimit_below(&rate_limit) ? LOG_WARNING : LOG_DEBUG, r,
"MESSAGE_ID=" SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR,
"DEVICE=%s", path,
LOG_MESSAGE("Failed to generate valid unit name from device path '%s', ignoring device: %m", path));
}
u = manager_get_unit(m, e); u = manager_get_unit(m, e);
if (u) { if (u) {
@ -576,10 +551,9 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool
(void) device_update_description(u, dev, path); (void) device_update_description(u, dev, path);
/* So the user wants the mount units to be bound to the device but a mount unit might has been seen /* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd
* by systemd before the device appears on its radar. In this case the device unit is partially * before the device appears on its radar. In this case the device unit is partially initialized and includes
* initialized and includes the deps on the mount unit but at that time the "bind mounts" flag wasn't * the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */
* present. Fix this up now. */
if (dev && device_is_bound_by_mounts(DEVICE(u), dev)) if (dev && device_is_bound_by_mounts(DEVICE(u), dev))
device_upgrade_mount_deps(u); device_upgrade_mount_deps(u);
@ -592,7 +566,7 @@ fail:
return r; return r;
} }
static void device_process_new(Manager *m, sd_device *dev) { static int device_process_new(Manager *m, sd_device *dev) {
const char *sysfs, *dn, *alias; const char *sysfs, *dn, *alias;
dev_t devnum; dev_t devnum;
int r; int r;
@ -600,13 +574,12 @@ static void device_process_new(Manager *m, sd_device *dev) {
assert(m); assert(m);
if (sd_device_get_syspath(dev, &sysfs) < 0) if (sd_device_get_syspath(dev, &sysfs) < 0)
return; return 0;
/* Add the main unit named after the sysfs path. If this one fails, don't bother with the rest, as /* Add the main unit named after the sysfs path */
* this one shall be the main device unit the others just follow. (Compare with how r = device_setup_unit(m, dev, sysfs, true);
* device_following() is implemented, see below, which looks for the sysfs device.) */ if (r < 0)
if (device_setup_unit(m, dev, sysfs, true) < 0) return r;
return;
/* Add an additional unit for the device node */ /* Add an additional unit for the device node */
if (sd_device_get_devname(dev, &dn) >= 0) if (sd_device_get_devname(dev, &dn) >= 0)
@ -622,11 +595,13 @@ static void device_process_new(Manager *m, sd_device *dev) {
if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/")) if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/"))
continue; continue;
/* Verify that the symlink in the FS actually belongs to this device. This is useful /* Verify that the symlink in the FS actually belongs
* to deal with conflicting devices, e.g. when two disks want the same * to this device. This is useful to deal with
* /dev/disk/by-label/xxx link because they have the same label. We want to make sure * conflicting devices, e.g. when two disks want the
* that the same device that won the symlink wins in systemd, so we check the device * same /dev/disk/by-label/xxx link because they have
* node major/minor */ * the same label. We want to make sure that the same
* device that won the symlink wins in systemd, so we
* check the device node major/minor */
if (stat(p, &st) >= 0 && if (stat(p, &st) >= 0 &&
((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) || ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
st.st_rdev != devnum)) st.st_rdev != devnum))
@ -638,7 +613,7 @@ static void device_process_new(Manager *m, sd_device *dev) {
/* Add additional units for all explicitly configured aliases */ /* Add additional units for all explicitly configured aliases */
if (sd_device_get_property_value(dev, "SYSTEMD_ALIAS", &alias) < 0) if (sd_device_get_property_value(dev, "SYSTEMD_ALIAS", &alias) < 0)
return; return 0;
for (;;) { for (;;) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
@ -647,9 +622,9 @@ static void device_process_new(Manager *m, sd_device *dev) {
if (r == 0) if (r == 0)
break; break;
if (r == -ENOMEM) if (r == -ENOMEM)
return (void) log_oom(); return log_oom();
if (r < 0) if (r < 0)
return (void) log_device_warning_errno(dev, r, "Failed to parse SYSTEMD_ALIAS property, ignoring: %m"); return log_device_warning_errno(dev, r, "Failed to parse SYSTEMD_ALIAS property: %m");
if (!path_is_absolute(word)) if (!path_is_absolute(word))
log_device_warning(dev, "SYSTEMD_ALIAS is not an absolute path, ignoring: %s", word); log_device_warning(dev, "SYSTEMD_ALIAS is not an absolute path, ignoring: %s", word);
@ -658,6 +633,8 @@ static void device_process_new(Manager *m, sd_device *dev) {
else else
(void) device_setup_unit(m, dev, word, false); (void) device_setup_unit(m, dev, word, false);
} }
return 0;
} }
static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) { static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) {
@ -721,7 +698,7 @@ static void device_update_found_by_sysfs(Manager *m, const char *sysfs, DeviceFo
device_update_found_one(d, found, mask); device_update_found_one(d, found, mask);
} }
static void device_update_found_by_name(Manager *m, const char *path, DeviceFound found, DeviceFound mask) { static int device_update_found_by_name(Manager *m, const char *path, DeviceFound found, DeviceFound mask) {
_cleanup_free_ char *e = NULL; _cleanup_free_ char *e = NULL;
Unit *u; Unit *u;
int r; int r;
@ -730,17 +707,18 @@ static void device_update_found_by_name(Manager *m, const char *path, DeviceFoun
assert(path); assert(path);
if (mask == 0) if (mask == 0)
return; return 0;
r = unit_name_from_path(path, ".device", &e); r = unit_name_from_path(path, ".device", &e);
if (r < 0) if (r < 0)
return (void) log_debug_errno(r, "Failed to generate unit name from device path, ignoring: %m"); return log_error_errno(r, "Failed to generate unit name from device path: %m");
u = manager_get_unit(m, e); u = manager_get_unit(m, e);
if (!u) if (!u)
return; return 0;
device_update_found_one(DEVICE(u), found, mask); device_update_found_one(DEVICE(u), found, mask);
return 0;
} }
static bool device_is_ready(sd_device *dev) { static bool device_is_ready(sd_device *dev) {
@ -881,7 +859,7 @@ static void device_enumerate(Manager *m) {
if (!device_is_ready(dev)) if (!device_is_ready(dev))
continue; continue;
device_process_new(m, dev); (void) device_process_new(m, dev);
if (sd_device_get_syspath(dev, &sysfs) < 0) if (sd_device_get_syspath(dev, &sysfs) < 0)
continue; continue;
@ -913,24 +891,27 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
} }
} }
static void device_remove_old_on_move(Manager *m, sd_device *dev) { static int device_remove_old(Manager *m, sd_device *dev) {
_cleanup_free_ char *syspath_old = NULL, *e = NULL; _cleanup_free_ char *syspath_old = NULL, *e = NULL;
const char *devpath_old; const char *devpath_old;
int r; int r;
r = sd_device_get_property_value(dev, "DEVPATH_OLD", &devpath_old); r = sd_device_get_property_value(dev, "DEVPATH_OLD", &devpath_old);
if (r < 0) if (r < 0) {
return (void) log_device_debug_errno(dev, r, "Failed to get DEVPATH_OLD= property on 'move' uevent, ignoring: %m"); log_device_debug_errno(dev, r, "Failed to get DEVPATH_OLD= property on 'move' uevent, ignoring: %m");
return 0;
}
syspath_old = path_join("/sys", devpath_old); syspath_old = path_join("/sys", devpath_old);
if (!syspath_old) if (!syspath_old)
return (void) log_oom(); return log_oom();
r = unit_name_from_path(syspath_old, ".device", &e); r = unit_name_from_path(syspath_old, ".device", &e);
if (r < 0) if (r < 0)
return (void) log_device_debug_errno(dev, r, "Failed to generate unit name from old device path, ignoring: %m"); return log_device_error_errno(dev, r, "Failed to generate unit name from old device path: %m");
device_update_found_by_sysfs(m, syspath_old, 0, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP); device_update_found_by_sysfs(m, syspath_old, 0, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP);
return 0;
} }
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) { static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
@ -958,7 +939,7 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
device_propagate_reload_by_sysfs(m, sysfs); device_propagate_reload_by_sysfs(m, sysfs);
if (action == SD_DEVICE_MOVE) if (action == SD_DEVICE_MOVE)
device_remove_old_on_move(m, dev); (void) device_remove_old(m, dev);
/* A change event can signal that a device is becoming ready, in particular if the device is using /* A change event can signal that a device is becoming ready, in particular if the device is using
* the SYSTEMD_READY logic in udev so we need to reach the else block of the following if, even for * the SYSTEMD_READY logic in udev so we need to reach the else block of the following if, even for
@ -974,7 +955,7 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
} else if (device_is_ready(dev)) { } else if (device_is_ready(dev)) {
device_process_new(m, dev); (void) device_process_new(m, dev);
r = swap_process_device_new(m, dev); r = swap_process_device_new(m, dev);
if (r < 0) if (r < 0)
@ -984,6 +965,7 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
/* The device is found now, set the udev found bit */ /* The device is found now, set the udev found bit */
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV); device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
} else } else
/* The device is nominally around, but not ready for us. Hence unset the udev bit, but leave /* The device is nominally around, but not ready for us. Hence unset the udev bit, but leave
* the rest around. */ * the rest around. */
@ -1046,6 +1028,8 @@ static int validate_node(Manager *m, const char *node, sd_device **ret) {
} }
void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFound mask) { void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFound mask) {
int r;
assert(m); assert(m);
assert(node); assert(node);
@ -1070,7 +1054,8 @@ void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFo
* under the name referenced in /proc/swaps or /proc/self/mountinfo. But first, let's validate if * under the name referenced in /proc/swaps or /proc/self/mountinfo. But first, let's validate if
* everything is alright with the device node. */ * everything is alright with the device node. */
if (validate_node(m, node, &dev) <= 0) r = validate_node(m, node, &dev);
if (r <= 0)
return; /* Don't create a device unit for this if the device node is borked. */ return; /* Don't create a device unit for this if the device node is borked. */
(void) device_setup_unit(m, dev, node, false); (void) device_setup_unit(m, dev, node, false);

View File

@ -492,7 +492,7 @@ fail:
return r; return r;
} }
static void swap_process_new(Manager *m, const char *device, int prio, bool set_flags) { static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL; _cleanup_(sd_device_unrefp) sd_device *d = NULL;
const char *dn, *devlink; const char *dn, *devlink;
struct stat st, st_link; struct stat st, st_link;
@ -500,22 +500,25 @@ static void swap_process_new(Manager *m, const char *device, int prio, bool set_
assert(m); assert(m);
if (swap_setup_unit(m, device, device, prio, set_flags) < 0) r = swap_setup_unit(m, device, device, prio, set_flags);
return; if (r < 0)
return r;
/* If this is a block device, then let's add duplicates for /* If this is a block device, then let's add duplicates for
* all other names of this block device */ * all other names of this block device */
if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode)) if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
return; return 0;
r = sd_device_new_from_stat_rdev(&d, &st); r = sd_device_new_from_stat_rdev(&d, &st);
if (r < 0) if (r < 0) {
return (void) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to allocate device for swap %s: %m", device); "Failed to allocate device for swap %s: %m", device);
return 0;
}
/* Add the main device node */ /* Add the main device node */
if (sd_device_get_devname(d, &dn) >= 0 && !streq(dn, device)) if (sd_device_get_devname(d, &dn) >= 0 && !streq(dn, device))
(void) swap_setup_unit(m, dn, device, prio, set_flags); swap_setup_unit(m, dn, device, prio, set_flags);
/* Add additional units for all symlinks */ /* Add additional units for all symlinks */
FOREACH_DEVICE_DEVLINK(d, devlink) { FOREACH_DEVICE_DEVLINK(d, devlink) {
@ -532,8 +535,10 @@ static void swap_process_new(Manager *m, const char *device, int prio, bool set_
st_link.st_rdev != st.st_rdev)) st_link.st_rdev != st.st_rdev))
continue; continue;
(void) swap_setup_unit(m, devlink, device, prio, set_flags); swap_setup_unit(m, devlink, device, prio, set_flags);
} }
return 0;
} }
static void swap_set_state(Swap *s, SwapState state) { static void swap_set_state(Swap *s, SwapState state) {
@ -1426,14 +1431,13 @@ int swap_process_device_new(Manager *m, sd_device *dev) {
assert(m); assert(m);
assert(dev); assert(dev);
if (sd_device_get_devname(dev, &dn) < 0) r = sd_device_get_devname(dev, &dn);
if (r < 0)
return 0; return 0;
r = unit_name_from_path(dn, ".swap", &e); r = unit_name_from_path(dn, ".swap", &e);
if (r < 0) { if (r < 0)
log_debug_errno(r, "Cannot convert device name '%s' to unit name, ignoring: %m", dn); return r;
return 0;
}
u = manager_get_unit(m, e); u = manager_get_unit(m, e);
if (u) if (u)

View File

@ -170,10 +170,6 @@ _SD_BEGIN_DECLARATIONS;
SD_ID128_MAKE(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93) SD_ID128_MAKE(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
#define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE_STR \ #define SD_MESSAGE_MOUNT_POINT_PATH_NOT_SUITABLE_STR \
SD_ID128_MAKE_STR(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93) SD_ID128_MAKE_STR(1b,3b,b9,40,37,f0,4b,bf,81,02,8e,13,5a,12,d2,93)
#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE \
SD_ID128_MAKE(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
#define SD_MESSAGE_DEVICE_PATH_NOT_SUITABLE_STR \
SD_ID128_MAKE_STR(01,01,90,13,8f,49,4e,29,a0,ef,66,69,74,95,31,aa)
#define SD_MESSAGE_NOBODY_USER_UNSUITABLE SD_ID128_MAKE(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c) #define SD_MESSAGE_NOBODY_USER_UNSUITABLE SD_ID128_MAKE(b4,80,32,5f,9c,39,4a,7b,80,2c,23,1e,51,a2,75,2c)
#define SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR \ #define SD_MESSAGE_NOBODY_USER_UNSUITABLE_STR \