# result MUST NOT be committed indiscriminately, but each automated
# change should be reviewed and only the appropriate ones commited.
#
-# To apply the coding style you can run the following command (assuming you
-# installed clang-format on your system):
+# The easiest way to apply the formatting to your changes ONLY,
+# is to use the git-clang-format script (usually installed with clang-format).
#
+# - Fixup formatting before committing
+# 1. Edit and stage your files.
+# 2. Run `git clang-format`.
+# 3. Verify + correct + (un)stage changes.
+# 4. Commit.
+#
+# - Fixup formatting after committing
+# 1. Commit your changes.
+# 2. Run `git clang-format HEAD~` - Refer the commit *before* your changes here.
+# 3. Verify + correct changes, `git difftool -d` can help here.
+# 4. Stage + commit, potentially with `--amend` (means to fixup the last commit).
+#
+# To run clang-format on all sourcefiles, use the following line:
# $ git ls-files 'src/*.[ch]' 'src/*.cc' | xargs clang-format -i -style=file
+#
# You can find more information on the different config parameters in this file here:
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
---
--- /dev/null
+---
+# vi: ts=2 sw=2 et:
+# See: https://google.github.io/oss-fuzz/getting-started/continuous-integration/
+
+name: CIFuzz
+on:
+ pull_request:
+ paths:
+ - '**/meson.build'
+ - '.github/workflows/**'
+ - 'meson_options.txt'
+ - 'src/**'
+ - 'test/fuzz/**'
+ - 'tools/oss-fuzz.sh'
+ push:
+ branches:
+ - master
+jobs:
+ Fuzzing:
+ runs-on: ubuntu-latest
+ if: github.repository == 'systemd/systemd'
+ steps:
+ - name: Build Fuzzers
+ id: build
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'systemd'
+ dry-run: false
+ allowed-broken-targets-percentage: 0
+ - name: Run Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'systemd'
+ fuzz-seconds: 600
+ dry-run: false
+ - name: Upload Crash
+ uses: actions/upload-artifact@v1
+ if: failure() && steps.build.outcome == 'success'
+ with:
+ name: artifacts
+ path: ./out/artifacts
python-lxml
qrencode
xz
+ zstd
Packages=
libidn2
libsmartcols-dev
libtool
libxkbcommon-dev
+ libzstd-dev
m4
meson
pkg-config
uuid-dev
xsltproc
xz-utils
+ zstd
Packages=
libqrencode4
libselinux-devel
libxkbcommon-devel
libxslt
+ libzstd-devel
lz4
lz4-devel
m4
tree
valgrind-devel
xz-devel
+ zstd
Packages=
- coreutils
- cryptsetup-libs
- kmod-libs
- e2fsprogs
- libidn2
- libseccomp
+ # libzstd can be dropped once the Fedora RPM gets a dependency on it
+ libzstd
+ # procps-ng provides a set of useful utilies (ps, free, etc)
procps-ng
- util-linux
BuildDirectory=mkosi.builddir
Cache=mkosi.cache
python3
python3-lxml
qrencode-devel
+ system-user-nobody
zlib-devel
# to satisfy tests
acl
glibc-locale
system-group-obsolete
+ system-user-bin
+ system-user-daemon
+ system-user-root
timezone
Packages=
libsmartcols-dev
libtool
libxkbcommon-dev
+ libzstd-dev
m4
meson
pkg-config
uuid-dev
xsltproc
xz-utils
+ zstd
Packages=
libqrencode3
their first output column with --no-legend. To hide the first column,
use --plain.
+ * The service manager gained basic support for cgroup v2 freezer. Units
+ can now be suspended or resumed either using new systemctl verbs,
+ freeze and thaw respectively, or via D-Bus.
+
CHANGES WITH 245:
* A new tool "systemd-repart" has been added, that operates as an
such files in version 243.
* systemd-logind will now validate access to the operation of changing
- the virtual terminal via a PolicyKit action. By default, only users
+ the virtual terminal via a polkit action. By default, only users
with at least one session on a local VT are granted permission.
* When systemd sets up PAM sessions that invoked service processes
* systemd-networkd's TUN support gained a new setting VnetHeader= for
tweaking Generic Segment Offload support.
+ * The address family for policy rules may be specified using the new
+ Family= option in the [RoutingPolicyRule] section.
+
* networkctl gained a new "delete" command for removing virtual network
devices, as well as a new "--stats" switch for showing device
statistics.
lookup is likely to trigger nss-ldap which in turn might use NSS to
ask systemd-resolved for hostname lookups. This will hence result in
a deadlock: a user name lookup in order to start
- systemd-resolved.service will result in a host name lookup for which
+ systemd-resolved.service will result in a hostname lookup for which
systemd-resolved.service needs to be started already. There are
multiple ways to work around this problem: pre-allocate the
"systemd-resolve" user on such systems, so that nss-ldap won't be
A/AAAA resource record for the "_gateway" hostname, pointing to the
current default IP gateway. Previously it did that for the "gateway"
name, hampering adoption, as some distributions wanted to leave that
- host name open for local use. The old behaviour may still be
+ hostname open for local use. The old behaviour may still be
requested at build time.
* systemd-networkd's [Address] section in .network files gained a new
again don't consider turning this on in your stable, LTS or
production release just yet. (Note that you have to enable
nss-resolve in /etc/nsswitch.conf, to actually use systemd-resolved
- and its DNSSEC mode for host name resolution from local
+ and its DNSSEC mode for hostname resolution from local
applications.)
* systemd-resolve conveniently resolves DANE records with the --tlsa
for a unit, as declared in the (usually vendor-supplied)
system preset files.
- * nss-myhostname will now resolve the single-label host name
+ * nss-myhostname will now resolve the single-label hostname
"gateway" to the locally configured default IP routing
gateways, ordered by their metrics. This assigns a stable
name to the used gateways, regardless which ones are
currently configured. Note that the name will only be
resolved after all other name sources (if nss-myhostname is
configured properly) and should hence not negatively impact
- systems that use the single-label host name "gateway" in
+ systems that use the single-label hostname "gateway" in
other contexts.
* systemd-inhibit now allows filtering by mode when listing
reported by uname()'s "machine" field.
* systemd-networkd now supports matching on the system
- virtualization, architecture, kernel command line, host name
+ virtualization, architecture, kernel command line, hostname
and machine ID.
* logind is now a lot more aggressive when suspending the
example, a line that creates /run/nologin).
* A new API "sd-resolve.h" has been added which provides a simple
- asynchronous wrapper around glibc NSS host name resolution
+ asynchronous wrapper around glibc NSS hostname resolution
calls, such as getaddrinfo(). In contrast to glibc's
getaddrinfo_a(), it does not use signals. In contrast to most
other asynchronous name resolution libraries, this one does
not reimplement DNS, but reuses NSS, so that alternate
- host name resolution systems continue to work, such as mDNS,
+ hostname resolution systems continue to work, such as mDNS,
LDAP, etc. This API is based on libasyncns, but it has been
cleaned up for inclusion in systemd.
when he over-mounts a non-empty directory.
* There are new specifiers that are resolved in unit files,
- for the host name (%H), the machine ID (%m) and the boot ID
+ for the hostname (%H), the machine ID (%m) and the boot ID
(%b).
Contributions from: Allin Cottrell, Auke Kok, Brandon Philips,
libselinux (optional)
liblzma (optional)
liblz4 >= 1.3.0 / 130 (optional)
+ libzstd >= 1.4.0 (optional)
libgcrypt (optional)
libqrencode (optional)
libmicrohttpd (optional)
[![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/>
[![Fuzzit Status](https://app.fuzzit.dev/badge?org_id=systemd&branch=master)](https://app.fuzzit.dev/orgs/systemd/dashboard)<br/>
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/systemd.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#systemd)<br/>
+[![CIFuzz](https://github.com/systemd/systemd/workflows/CIFuzz/badge.svg)](https://github.com/systemd/systemd/actions)<br/>
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
[![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
[![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>
Features:
+* machined: add API to acquire UID range. add API to mount/dissect loopback
+ file. Both protected by PK. Then make nspawn use these APIs to run
+ unprivileged containers. i.e. push the truly privileged bits into machined,
+ so that the client side can remain entirely unprivileged, with SUID or
+ anything like that.
+
+* add "throttling" to sd-event event sources: optionally, when we wake up too
+ often for one, let's turn it off entirely for a while. Use that for the
+ /proc/self/mountinfo logic.
+
+* move our systemd-user PAM snippet to /usr/, which PAM appears to support
+ these days
+
+* nspawn: support time namespaces
+
+* pid1: Move to tracking of main pid/control pid of units per pidfd
+
+* pid1: support new clone3() fork-into-cgroup feature
+
+* pid1: also remove PID files of a service when the service starts, not just
+ when it exits
+
+* make "systemd-dissect" an official supported tool, i.e. move to /usr/bin/ and
+ provide man page. Given that we now have a tool that can generate images like
+ this, it's useful to have one that can dump contents of them, too.
+
+* All tools that support --root= should also learn --image= so that they can
+ operate on disk images directly. Specifically: bootctl, firstboot, tmpfiles,
+ sysusers, systemctl, repart, journalctl, coredumpctl.
+
+* per-service credential system. Specifically: add LoadCredential= (for loading
+ cred from file), AcquireCredential= (for asking user for cred, via
+ ask-password), PassCredential= (for passing on credential systemd itself
+ got). Then, place credentials in a per-service, immutable ramfs instance (so
+ that it cannot be swapped out), destroy after use. Also pass via keyring
+ (with graceful fallback to cover for containers). Define CredentialPath= for
+ defining subdir of /run/credentials/ where to place it. Set $CREDENTIAL_PATH
+ env var for services to the result. Also pass via fd passing (optionally).
+
+* homed: add native recovery key support. use 48 lowercase modhex characters
+ (192bit), show qr code of it, include pattern expression in user record.
+
+* homed: introduce "degraded" state for home directories that weren't cleanly
+ unmounted (use xattr we add and remove on the loop back file)
+
+* homed: during login resize fs automatically towards size goal. Specifically,
+ resize to diskSize if possible, but leave a certain amount (configured by a
+ new value diskLeaveFreeSize) of space free on the backing fs.
+
+* homed: permit multiple user record signing keys to be used locally, and pick
+ the right one for signing records automatically depending on a pre-existing
+ signature
+
+* homed: add a way to "adopt" a home directory, i.e. strip foreign signatures
+ and insert a local signature instead.
+
+* homed: as an extension to the directory+subvolume backend: if located on
+ especially marked fs, then sync down password into LUKS header of that fs,
+ and always verify passwords against it too. Bootstrapping is a problem
+ though: if noone is logged in (or no other user even exists yet), how do you
+ unlock the volume in order to create the first user and add the first pw.
+
+* homed: support new FS_IOC_ADD_ENCRYPTION_KEY ioctl for setting up fscrypt
+
+* busctl: maybe expose a verb "ping" for pinging a dbus service to see if it
+ exists and responds.
+
* homed: maybe pre-create ~/.cache as subvol so that it can have separate quota
easily?
-* journalctl --image= which is like --root= but operates on disk images
-
* when systemd-nspawn and suchlike dissect an OS image, and there are multiple
root partitions, do an strverscmp() on the partition label and boot
first. That is inspired how sd-boot figures out which kernel to boot, and
thus allows defining OS images which can be A/B updated and we default to the
newest version automatically, both in nspawn and in sd-boot
-* drop sd_bus_message_set_priority() from sd-bus API and documentation as much
- as we can, it's a kdbus left-over and unlikely to come back on AF_UNIX, since
- it's not really implementable there.
-
* cryptsetup/homed: also support FIDO2 HMAC password logic for unlocking
devices. (see: https://github.com/mjec/fido2-hmac-secret)
* by default, in systemd --user service bump the OOMAdjust to 100, as privs
allow so that systemd survives
-* honour specifiers in unit files that resolve to some very basic
- /etc/os-release data, such as ID, VERSION_ID, BUILD_ID, VARIANT_ID.
-
* cryptsetup: allow encoding key directly in /etc/crypttab, maybe with a
"base64:" prefix. Useful in particular for pkcs11 mode.
* systemd-repart: make it a static checker during early boot for existence and
absence of other partitions for trusted boot environments
-* systemd-repart: when no configuration is found, exit early do not check
- partition table, so that it is safe to run in the initrd on any system
-
* systemd-repart: allow config of partition uuid
* userdb: allow username prefix searches in varlink API, allow realname and
realname substr searches in varlink API
+* userdb: allow uid/gid range checks
+
* userdb: allow existence checks
-* pid: activation by journal search expression
+* pid1: activation by journal search expression
* when switching root from initrd to host, set the machine_id env var so that
if the host has no machine ID set yet we continue to use the random one the
that are linked to these places instead of copied. After all they are
constant vendor data.
-* maybe add kernel cmdline params: 1) to force first-boot mode + 2) to force
- random seed crediting
+* maybe add kernel cmdline params: to force random seed crediting
* nspawn: on cgroupsv1 issue cgroup empty handler process based on host events,
so that we make cgroup agent logic safe
- rollback when resize fails mid-operation
- GNOME's side for forget key on suspend (requires rework so that lock screen runs outside of uid)
- resize on login?
- - fstrim on logout?
- shrink fs on logout?
- update LUKS password on login if we find there's a password that unlocks the JSON record but not the LUKS device.
- create on activate?
* support projid-based quota in machinectl for containers
-* maybe use SOURCE_DATE_EPOCH (i.e. the env var the reproducible builds folks
- introduced) as the RTC epoch, instead of the mtime of NEWS.
-
* add a way to lock down cgroup migration: a boolean, which when set for a unit
makes sure the processes in it can never migrate out of it
* networkd:
- add more keys to [Route] and [Address] sections
- add support for more DHCPv4 options (and, longer term, other kinds of dynamic config)
- - add proper initrd support (in particular generate .network/.link files based on /proc/cmdline)
- add reduced [Link] support to .network files
- - add Scope= parsing option for [Network]
- properly handle routerless dhcp leases
- work with non-Ethernet devices
- - add support for more bond options
- dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from?
- the DHCP lease data (such as NTP/DNS) is still made available when
a carrier is lost on a link. It should be removed instantly.
- expose in the API the following bits:
- - option 15, domain name and/or option 119, search list
- - option 12, host name and/or option 81, fqdn
+ - option 15, domain name
+ - option 12, hostname and/or option 81, fqdn
- option 123, 144, geolocation
- option 252, configure http proxy (PAC/wpad)
- provide a way to define a per-network interface default metric value
- allow Name= to be specified repeatedly in the [Match] section. Maybe also
support Name=foo*|bar*|baz ?
- duplicate address check for static IPs (like ARPCHECK in network-scripts)
- - allow DUID/IAID to be customized, see issue #394.
- whenever uplink info changes, make DHCP server send out FORCERENEW
-* networkd-wait-online:
- - make operstates to wait for configurable?
-
* dhcp:
- figure out how much we can increase Maximum Message Size
- natively watch for dbus-*.service symlinks (PENDING)
- teach dbus to activate all services it finds in /etc/systemd/services/org-*.service
-* fix alsa mixer restore to not print error when no config is stored
-
* make cryptsetup lower --iter-time
-* patch kernel for xattr support in /dev, /proc/, /sys?
-
* kernel: add device_type = "fb", "fbcon" to class "graphics"
* /usr/bin/service should actually show the new command line
* fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus=
-* fedora: F20: go timer units all the way, leave cron.daily for cron
-
* neither pkexec nor sudo initialize environ[] from the PAM environment?
* fedora: update policy to declare access mode and ownership of unit files to root:root 0644, and add an rpmlint check for it
Proszę zauważyć, że brak pamięci mógł nie zostać spowodowany
przez jednostkę @UNIT@.
+
+-- b61fdac612e94b9182285b998843061f
+Subject: Przyjmowanie nazwy użytkownika/grupy @USER_GROUP_NAME@, która nie zgadza się ze ścisłymi regułami nazw użytkowników/grup.
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+Podano nazwę użytkownika/grupy @USER_GROUP_NAME@, co zostało przyjęte
+zgodnie z rozluźnionymi regułami nazw użytkowników/grup, ale nie spełnia
+ścisłych reguł.
+
+Ścisłe reguły nazw użytkowników/grup zapisane jako wyrażenie regularne to:
+
+^[a-zA-Z_][a-zA-Z0-9_-]{0,30}$
+
+Rozluźnione reguły nazw użytkowników/grup przyjmują wszystkie nazwy,
+oprócz pustego ciągu, nazw zawierających bajty NUL, znaki kontrolne,
+dwukropki lub ukośniki, nazw niebędących prawidłowym tekstem UTF-8,
+nazw z początkową lub końcową spacją, ciągów „.” lub „..”, ciągów
+zawierających tylko cyfry lub ciągów zaczynających się myślnikiem
+i zawierających oprócz niego tylko cyfry.
+
+https://systemd.io/USER_NAMES zawiera więcej informacji o ścisłych
+i rozluźnionych regułach nazw użytkowników/grup.
## Deadlocks
-- Do not issue NSS requests (that includes user name and host name lookups)
+- Do not issue NSS requests (that includes user name and hostname lookups)
from PID 1 as this might trigger deadlocks when those lookups involve
synchronously talking to services that we would need to start up.
home directory temporarily and copy the data in.
```
- homectl with foobar -- rsync -aHAXv --delete-during /home/foobar.saved/ .
+ homectl with foobar -- rsync -aHAXv --remove-source-files /home/foobar.saved/ .
```
This mounts the home directory of the user, and then runs the specified
new. The new home directory is the working directory of the invoked `rsync`
process. We are invoking this command as root, hence the `rsync` runs as
root too. When the `rsync` command completes the home directory is
- automatically unmounted again. Since we used `--delete-during` all files
+ automatically unmounted again. Since we used `--remove-source-files` all files
copied are removed from the old home directory as the copy progresses. After
the command completes the old home directory should be empty. Let's remove
it hence:
[`systemd.special(7)`](https://www.freedesktop.org/software/systemd/man/systemd.special.html)
defines the `graphical-session.target` and `graphical-session-pre.target` to
allow cross-desktop integration. Furthermore, systemd defines the three base
-slices `background`, `apps` and `session`.
+slices `background`, `app` and `session`.
All units should be placed into one of these slices depending on their purposes:
* `session.slice`: Contains only processes essential to run the user's graphical session
- * `apps.slice`: Contains all normal applications that the user is running
+ * `app.slice`: Contains all normal applications that the user is running
* `background.slice`: Useful for low-priority background tasks
The purpose of this grouping is to assign different priorities to the
or assigning different memory/CPU/IO priorities to ensure that the session
runs smoothly under load.
-TODO: Will there be a default to place units into e.g. `apps.slice` by default
+TODO: Will there be a default to place units into e.g. `app.slice` by default
rather than the root slice?
## XDG standardization for applications
To ensure cross-desktop compatibility and encourage sharing of good practices,
desktop environments should adhere to the following conventions:
- * Application units should follow the scheme `apps-<launcher>-<ApplicationID>-<RANDOM>.service`,
- e.g. `apps-gnome-org.gnome.Evince-12345.service`,
- `apps-flatpak-org.telegram.desktop-12345.service` or `apps-KDE-org.kde.okular-12345.service`.
+ * Application units should follow the scheme `app-<launcher>-<ApplicationID>-<RANDOM>.service`,
+ e.g. `app-gnome-org.gnome.Evince-12345.service`,
+ `app-flatpak-org.telegram.desktop-12345.service` or `app-KDE-org.kde.okular-12345.service`.
* Using `.service` units instead of `.scope` units, i.e. allowing systemd to
start the process on behalf of the caller,
instead of the caller starting the process and letting systemd know about it,
contain a `-` character.
This has the following advantages:
- * Using the `apps-<launcher>-` prefix means that the unit defaults can be
+ * Using the `app-<launcher>-` prefix means that the unit defaults can be
adjusted using desktop environment specific drop-in files.
* The application ID can be retrieved by stripping the prefix and postfix.
This in turn should map to the corresponding `.desktop` file when available
TODO: Define the name of slices that should be used.
-This could be `apps-<launcher>-<ApplicationID>-<RANDOM>.slice`.
+This could be `app-<launcher>-<ApplicationID>-<RANDOM>.slice`.
TODO: Does it really make sense to insert the `<launcher>`? In GNOME I am
currently using a drop-in to configure `BindTo=graphical-session.target`,
* Should application lifetime be bound to the session?
* May the user have applications that do not belong to the graphical session (e.g. launched from SSH)?
- * Could we maybe add a default `apps-.service.d` drop-in configuration?
+ * Could we maybe add a default `app-.service.d` drop-in configuration?
## XDG autostart integration
the file system, the home directory is automatically and recursively `chown()`ed
to the correct UID.
-Depending on the `discard` setting of the user record either the backing
+Depending on the `luksDiscard` setting of the user record either the backing
loopback file is `fallocate()`ed during activation, or the mounted file system
is `FITRIM`ed after mounting, to ensure the setting is correctly enforced.
+
+When deactivating a home directory, the file system or block device is trimmed
+or extended as configured in the `luksOfflineDiscard` setting of the user
+record.
--- /dev/null
+---
+title: Password Agents
+category: Interfaces
+layout: default
+---
+
+# Password Agents
+
+systemd 12 and newer support lightweight password agents which can be used to query the user for system-level passwords or passphrases. These are passphrases that are not related to a specific user, but to some kind of hardware or service. Right now this is used exclusively for encrypted hard-disk passphrases but later on this is likely to be used to query passphrases of SSL certificates at Apache startup time as well. The basic idea is that a system component requesting a password entry can simply drop a simple .ini-style file into `/run/systemd/ask-password` which multiple different agents may watch via `inotify()`, and query the user as necessary. The answer is then sent back to the querier via an `AF_UNIX`/`SOCK_DGRAM` socket. Multiple agents might be running at the same time in which case they all should query the user and the agent which answers first wins. Right now systemd ships with the following passphrase agents:
+
+* A Plymouth agent used for querying passwords during boot-up
+* A console agent used in similar situations if Plymouth is not available
+* A GNOME agent which can be run as part of the normal user session which pops up a notification message and icon which when clicked receives the passphrase from the user. This is useful and necessary in case an encrypted system hard-disk is plugged in when the machine is already up.
+* A [`wall(1)`](http://man7.org/linux/man-pages/man1/wall.1.html) agent which sends wall messages as soon as a password shall be entered.
+* A simple tty agent which is built into "`systemctl start`" (and similar commands) and asks passwords to the user during manual startup of a service
+* A simple tty agent which can be run manually to respond to all queued passwords
+
+It is easy to write additional agents. The basic algorithm to follow looks like this:
+
+* Create an inotify watch on /run/systemd/ask-password, watch for `IN_CLOSE_WRITE|IN_MOVED_TO`
+* Ignore all events on files in that directory that do not start with "`ask.`"
+* As soon as a file named "`ask.xxxx`" shows up, read it. It's a simple `.ini` file that may be parsed with the usual parsers. The `xxxx` suffix is randomized.
+* Make sure to ignore unknown `.ini` file keys in those files, so that we can easily extend the format later on.
+* You'll find the question to ask the user in the `Message=` field in the `[Ask]` section. It is a single-line string in UTF-8, which might be internationalized (by the party that originally asks the question, not by the agent).
+* You'll find an icon name (following the XDG icon naming spec) to show next to the message in the `Icon=` field in the `[Ask]` section
+* You'll find the PID of the client asking the question in the `PID=` field in the `[Ask]` section (Before asking your question use `kill(PID, 0)` and ignore the file if this returns `ESRCH`; there's no need to show the data of this field but if you want to you may)
+* `Echo=` specifies whether the input should be obscured. If this field is missing or is `Echo=0`, the input should not be shown.
+* The socket to send the response to is configured via `Socket=` in the `[Ask]` section. It is a `AF_UNIX`/`SOCK_DGRAM` socket in the file system.
+* Ignore files where the time specified in the `NotAfter=` field in the `[Ask]` section is in the past. The time is specified in usecs, and refers to the `CLOCK_MONOTONIC` clock. If `NotAfter=` is `0`, no such check should take place.
+* Make sure to hide a password query dialog as soon as a) the `ask.xxxx` file is deleted, watch this with inotify. b) the `NotAfter=` time elapses, if it is set `!= 0`.
+* Access to the socket is restricted to privileged users. To acquire the necessary privileges to send the answer back, consider using PolicyKit. In fact, the GNOME agent we ship does that, and you may simply piggyback on that, by executing "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 1 /path/to/socket`" or "`/usr/bin/pkexec /lib/systemd/systemd-reply-password 0 /path/to/socket`" and writing the password to its standard input. Use '`1`' as argument if a password was entered by the user, or '`0`' if the user canceled the request.
+* If you do not want to use PK ensure to acquire the necessary privileges in some other way and send a single datagram to the socket consisting of the password string either prefixed with "`+`" or with "`-`" depending on whether the password entry was successful or not. You may but don't have to include a final `NUL` byte in your message.
+
+Again, it is essential that you stop showing the password box/notification/status icon if the `ask.xxx` file is removed or when `NotAfter=` elapses (if it is set `!= 0`)!
+
+It may happen that multiple password entries are pending at the same time. Your agent needs to be able to deal with that. Depending on your environment you may either choose to show all outstanding passwords at the same time or instead only one and as soon as the user replied to that one go on to the next one.
+
+You may test this all with manually invoking the "`systemd-ask-password`" tool on the command line. Pass `--no-tty` to ensure the password is asked via the agent system. Note that only privileged users may use this tool (after all this is intended purely for system-level passwords).
+
+If you write a system level agent a smart way to activate it is using systemd `.path` units. This will ensure that systemd will watch the `/run/systemd/ask-password` directory and spawn the agent as soon as that directory becomes non-empty. In fact, the console, wall and Plymouth agents are started like this. If systemd is used to maintain user sessions as well you can use a similar scheme to automatically spawn your user password agent as well. (As of this moment we have not switched any DE over to use systemd for session management, however.)
| [Boot Loader interface](https://systemd.io/BOOT_LOADER_INTERFACE) | EFI variables | yes | yes | gummiboot | yes | - | no |
| [Service bus API](https://www.freedesktop.org/wiki/Software/systemd/dbus) | D-Bus | yes | yes | system-config-services | no | - | no |
| [logind](https://www.freedesktop.org/wiki/Software/systemd/logind) | D-Bus | yes | yes | GNOME | no | - | no |
-| [sd-login.h API](https://www.freedesktop.org/software/systemd/man/sd-login.html) | C Library | yes | yes | GNOME, PolicyKit, ... | no | - | no |
+| [sd-login.h API](https://www.freedesktop.org/software/systemd/man/sd-login.html) | C Library | yes | yes | GNOME, polkit, ... | no | - | no |
| [sd-daemon.h API](https://www.freedesktop.org/software/systemd/man/sd-daemon.html) | C Library or Drop-in | yes | yes | numerous | yes | - | yes |
| [sd-id128.h API](https://www.freedesktop.org/software/systemd/man/sd-id128.html) | C Library | yes | yes | - | yes | - | no |
| [sd-journal.h API](https://www.freedesktop.org/software/systemd/man/sd-journal.html) | C Library | yes | yes | - | maybe | - | no |
# Reporting of Security Vulnerabilities
-If you discover a security vulnerability, we'd appreciate a non-public disclosure. The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public. If you need to reach systemd developers in a non-public way, report the issue to the [systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list. The disclosure will be coordinated with distributions.
+If you discover a security vulnerability, we'd appreciate a non-public disclosure. systemd developers can be contacted privately on the **[systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list**. The disclosure will be coordinated with distributions.
+
+(The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public.)
+
+Subscription to the systemd-security mailing list is open to **regular systemd contributors and people working in the security teams of various distributions**. Those conditions should be backed by publicly accessible information (ideally, a track of posts and commits from the mail address in question). If you fall into one of those categories and wish to be subscribed, submit a **[subscription request](https://www.redhat.com/mailman/listinfo/systemd-security)**.
✓ SloppyOptions=
✓ LazyUnmount=
✓ ForceUnmount=
+✓ ReadWriteOnly=
```
## Automount Unit Settings
any user management UI to expose them directly.
`systemd-homed` exposes APIs to add, remove and make changes to local users via
-D-Bus, with full PolicyKit hook-up. On the command line this is exposed via the
+D-Bus, with full [polkit](https://www.freedesktop.org/software/polkit/docs/latest/)
+hook-up. On the command line this is exposed via the
`homectl` command. A graphical UI that exposes similar functionality would be
very useful, exposing the various new account settings, and in particular
providing a stream-lined UI for enrolling new-style authentication tokens such
addition, depending on this setting an `FITRIM` or `fallocate()` operation is
executed to make sure the image matches the selected option.
+`luksOfflineDiscard` → A boolean. Similar to `luksDiscard`, it controls whether
+to trim/allocate the file system/backing file when deactivating the home
+directory.
+
`luksCipher` → A string, indicating the cipher to use for the LUKS storage mechanism.
`luksCipherMode` → A string, selecting the cipher mode to use for the LUKS storage mechanism.
`mountNoDevices`, `mountNoSuid`, `mountNoExecute`, `cifsDomain`,
`cifsUserName`, `cifsService`, `imagePath`, `uid`, `gid`, `memberOf`,
`fileSystemType`, `partitionUuid`, `luksUuid`, `fileSystemUuid`, `luksDiscard`,
-`luksCipher`, `luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`,
-`luksPbkdfType`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`,
-`luksPbkdfParallelThreads`, `rateLimitIntervalUSec`, `rateLimitBurst`,
-`enforcePasswordPolicy`, `autoLogin`, `stopDelayUSec`, `killProcesses`,
-`passwordChangeMinUSec`, `passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
+`luksOfflineDiscard`, `luksOfflineDiscard`, `luksCipher`, `luksCipherMode`,
+`luksVolumeKeySize`, `luksPbkdfHashAlgorithm`, `luksPbkdfType`,
+`luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`, `luksPbkdfParallelThreads`,
+`rateLimitIntervalUSec`, `rateLimitBurst`, `enforcePasswordPolicy`,
+`autoLogin`, `stopDelayUSec`, `killProcesses`, `passwordChangeMinUSec`,
+`passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
`passwordChangeInactiveUSec`, `passwordChangeNow`, `pkcs11TokenUri`.
## Fields in the `binding` section
# Lenovo Thinkpad T490
evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:*
- EVDEV_ABS_00=::57
- EVDEV_ABS_01=::33
- EVDEV_ABS_35=::57
- EVDEV_ABS_36=::33
+ EVDEV_ABS_00=::44
+ EVDEV_ABS_01=::52
+ EVDEV_ABS_35=::44
+ EVDEV_ABS_36=::52
# Lenovo Legion Y9000X2020
evdev:name:MSFT0001:02 04F3:304B Touchpad:dmi:*svnLENOVO:*pvrLenovoLegionY9000X2020*
# Lite-On Tech IBM USB Travel Keyboard with Ultra Nav Mouse
id-input:modalias:input:b0003v04B3p301Ee0100-e0,1,2,4*
ID_INPUT_POINTINGSTICK=1
+
+# Logitech Ultrathin Touch Mouse
+id-input:modalias:input:b0005v046DpB00De0700*
+ ID_INPUT_MOUSE=1
# HP EliteBook 725 G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:pvr*
+# HP EliteBook 840 G1
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBook840G1:pvr*
# HP ProBook 440 G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP440G2:pvr*
# several HP ProBooks 4xx
KEYBOARD_KEY_c103a=prog3 # Smartkey C → XF86Launch3
KEYBOARD_KEY_c103b=prog4 # Smartkey D → XF86Launch4
+# Logitech K811
+evdev:input:b0005v046DpB317*
+ KEYBOARD_KEY_70047=brightnessdown
+ KEYBOARD_KEY_70048=brightnessup
+
# iTouch
evdev:input:b0003v046DpC308*
KEYBOARD_KEY_90001=shop # Shopping
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
+# Chuwi HiBook Pro (CWI526)
+sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
+ ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
+
# Chuwi CoreBook
# Chuwi CoreBook does not have its product name filled, so we
# match the entire dmi-alias
sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+# caroline board (Samsung Chromebook Pro) reports itself as svnGoogle
+sensor:modalias:platform:cros-ec-accel:dmi:*:svnGoogle:pnCaroline*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+
#########################################
# GP-electronic
#########################################
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
# Medion Akoya E2215T MD60198
+sensor:modalias:acpi:KIOX000A*:dmi:*svnMEDION:pnE2215TMD60198:*
# Medion Akoya E3216 MD60900
# Medion Akoya E3221 MD61237
# Medion Akoya E2292 MD63390
MOUSE_DPI=400@125 *800@125 1600@125 3200@125 400@500 800@500 1600@500 3200@500 400@1000 800@1000 1600@1000 3200@1000
MOUSE_WHEEL_CLICK_COUNT=16
MOUSE_WHEEL_CLICK_ANGLE=23
+
+# Zowie ZA12
+mouse:usb:v1af3p0001:name:Kingsis Peripherals ZOWIE Gaming mouse:
+ MOUSE_DPI=400@125 *800@125 1600@125 3200@125 400@500 800@500 1600@500 3200@500 400@1000 800@1000 1600@1000 3200@1000
+ MOUSE_WHEEL_CLICK_COUNT=16
+ MOUSE_WHEEL_CLICK_ANGLE=23
character are ignored. Each of the remaining lines describes one
encrypted block device. Fields are delimited by white space.</para>
- <para>Each line is in the form<programlisting><replaceable>name</replaceable> <replaceable>encrypted-device</replaceable> <replaceable>password</replaceable> <replaceable>options</replaceable></programlisting>
+ <para>Each line is in the form<programlisting><replaceable>volume-name</replaceable> <replaceable>encrypted-device</replaceable> <replaceable>key-file</replaceable> <replaceable>options</replaceable></programlisting>
The first two fields are mandatory, the remaining two are
optional.</para>
it is opened as a LUKS device; otherwise, it is assumed to be in
raw dm-crypt (plain mode) format.</para>
- <para>The first field contains the name of the resulting encrypted
- block device; the device is set up within
- <filename>/dev/mapper/</filename>.</para>
+ <para>The first field contains the name of the resulting encrypted volume; its block device is set up
+ below <filename>/dev/mapper/</filename>.</para>
<para>The second field contains a path to the underlying block
device or file, or a specification of a block device via
<literal>UUID=</literal> followed by the UUID.</para>
- <para>The third field specifies the encryption password. If the
- field is not present or the password is set to
- <literal>none</literal> or <literal>-</literal>, the password has
- to be manually entered during system boot. Otherwise, the field is
- interpreted as an absolute path to a file containing the encryption
- password. For swap encryption, <filename>/dev/urandom</filename>
- or the hardware device <filename>/dev/hw_random</filename> can be
- used as the password file; using <filename>/dev/random</filename>
- may prevent boot completion if the system does not have enough
- entropy to generate a truly random encryption key.</para>
+ <para>The third field specifies an absolute path to a file to read the encryption key from. If the field
+ is not present or set to <literal>none</literal> or <literal>-</literal>, a key file named after the
+ volume to unlock (i.e. the first column of the line), suffixed with <filename>.key</filename> is
+ automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename> and
+ <filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to be
+ manually entered during system boot. For swap encryption, <filename>/dev/urandom</filename> may be used
+ as key file.</para>
<para>The fourth field, if present, is a comma-delimited list of
options. The following options are recognized:</para>
size is then given by the key size.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>keyfile-erase</option></term>
+
+ <listitem><para>If enabled, the specified key file is erased after the volume is activated or when
+ activation fails. This is in particular useful when the key file is only acquired transiently before
+ activation (e.g. via a file in <filename>/run/</filename>, generated by a service running before
+ activation), and shall be removed after use. Defaults to off.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>key-slot=</option></term>
before it is used to unlock the LUKS volume.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>try-empty-password=</option></term>
+
+ <listitem><para>Takes a boolean argument. If enabled, right before asking the user for a password it
+ is first attempted to unlock the volume with an empty password. This is useful for systems that are
+ initialized with an encrypted volume with only an empty password set, which shall be replaced with a
+ suitable password during first boot, but after activation.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>x-systemd.device-timeout=</option></term>
--- /dev/null
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="systemd.directives" conditional="HAVE_PYTHON">
+ <refentryinfo>
+ <title>systemd.directives</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd.directives</refentrytitle>
+ <manvolnum>7</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd.directives</refname>
+ <refpurpose>Index of configuration directives</refpurpose>
+ </refnamediv>
+
+ <refsect1>
+ <title>Unit directives</title>
+
+ <para>Directives for configuring units, used in unit files.</para>
+
+ <variablelist id='unit-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>Options on the kernel command line</title>
+
+ <para>Kernel boot options for configuring the behaviour of the systemd process.</para>
+
+ <variablelist id='kernel-commandline-options' />
+ </refsect1>
+
+ <refsect1>
+ <title>Environment variables</title>
+
+ <para>Environment variables understood by the systemd manager and other programs and environment
+ variable-compatible settings.</para>
+
+ <variablelist id='environment-variables' />
+ </refsect1>
+
+ <refsect1>
+ <title>EFI variables</title>
+
+ <para>EFI variables understood by
+ <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ and other programs.</para>
+
+ <variablelist id='efi-variables' />
+ </refsect1>
+
+ <refsect1>
+ <title>Home Area/User Account directives</title>
+
+ <para>Directives for configuring home areas and user accounts via
+ <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+ <variablelist id='home-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>UDEV directives</title>
+
+ <para>Directives for configuring systemd units through the udev database.</para>
+
+ <variablelist id='udev-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>Network directives</title>
+
+ <para>Directives for configuring network links through the net-setup-link udev builtin and networks
+ through systemd-networkd.</para>
+
+ <variablelist id='network-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>Journal fields</title>
+
+ <para>Fields in the journal events with a well known meaning.</para>
+
+ <variablelist id='journal-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>PAM configuration directives</title>
+
+ <para>Directives for configuring PAM behaviour.</para>
+
+ <variablelist id='pam-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title><filename>/etc/crypttab</filename> and
+ <filename>/etc/fstab</filename> options</title>
+
+ <para>Options which influence mounted filesystems and encrypted volumes.</para>
+
+ <variablelist id='fstab-options' />
+ </refsect1>
+
+ <refsect1>
+ <title><citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ directives</title>
+
+ <para>Directives for configuring systemd-nspawn containers.</para>
+
+ <variablelist id='nspawn-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>Program configuration options</title>
+
+ <para>Directives for configuring the behaviour of the systemd process and other tools through
+ configuration files.</para>
+
+ <variablelist id='config-directives' />
+ </refsect1>
+
+ <refsect1>
+ <title>Command line options</title>
+
+ <para>Command-line options accepted by programs in the systemd suite.</para>
+
+ <variablelist id='options' />
+ </refsect1>
+
+ <refsect1>
+ <title>Constants</title>
+
+ <para>Various constant used and/or defined by systemd.</para>
+
+ <variablelist id='constants' />
+ </refsect1>
+
+ <refsect1>
+ <title>Miscellaneous options and directives</title>
+
+ <para>Other configuration elements which don't fit in any of the above groups.</para>
+
+ <variablelist id='miscellaneous' />
+ </refsect1>
+
+ <refsect1>
+ <title>Specifiers</title>
+
+ <para>Short strings which are substituted in configuration directives.</para>
+
+ <variablelist id='specifiers' />
+ </refsect1>
+
+ <refsect1>
+ <title>Files and directories</title>
+
+ <para>Paths and file names referred to in the documentation.</para>
+
+ <variablelist id='filenames' />
+ </refsect1>
+
+ <refsect1>
+ <title>D-Bus interfaces</title>
+
+ <para>Interfaces exposed over D-Bus.</para>
+
+ <variablelist id='dbus-interface' />
+ </refsect1>
+
+ <refsect1>
+ <title>D-Bus methods</title>
+
+ <para>Methods exposed in the D-Bus interface.</para>
+
+ <variablelist id='dbus-method' />
+ </refsect1>
+
+ <refsect1>
+ <title>D-Bus properties</title>
+
+ <para>Properties exposed in the D-Bus interface.</para>
+
+ <variablelist id='dbus-property' />
+ </refsect1>
+
+ <refsect1>
+ <title>D-Bus signals</title>
+
+ <para>Signals emitted in the D-Bus interface.</para>
+
+ <variablelist id='dbus-signal' />
+ </refsect1>
+
+ <refsect1>
+ <title>Colophon</title>
+ <para id='colophon' />
+ </refsect1>
+</refentry>
<listitem><para>Selects the storage mechanism to use for this home directory. Takes one of
<literal>luks</literal>, <literal>fscrypt</literal>, <literal>directory</literal>,
<literal>subvolume</literal>, <literal>cifs</literal>. For details about these mechanisms, see
- above. If a new home directory is created and the storage type is not specifically specified defaults
- to <literal>luks</literal> if supported, <literal>subvolume</literal> as first fallback if supported,
- and <literal>directory</literal> if not.</para></listitem>
+ above. If a new home directory is created and the storage type is not specifically specified,
+ <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ defines which default storage to use.</para></listitem>
</varlistentry>
<varlistentry>
<listitem><para>When LUKS2 storage is used configures the file system type to use inside the home
directory LUKS2 container. One of <literal>ext4</literal>, <literal>xfs</literal>,
- <literal>btrfs</literal>. If not specified defaults to <literal>ext4</literal>. Note that
- <literal>xfs</literal> is not recommended as its support for file system resizing is too
- limited.</para></listitem>
+ <literal>btrfs</literal>. If not specified
+ <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ defines which default file system type to use. Note that <literal>xfs</literal> is not recommended as
+ its support for file system resizing is too limited.</para></listitem>
</varlistentry>
<varlistentry>
loopback file) the discard logic defaults to on.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--luks-offline-discard=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>Similar to <option>--luks-discard=</option>, controls the trimming of the file
+ system. However, while <option>--luks-discard=</option> controls what happens when the home directory
+ is active, <option>--luks-offline-discard=</option> controls what happens when it becomes inactive,
+ i.e. whether to trim/allocate the storage when deactivating the home directory. This option defaults
+ to on, to ensure disk space is minimized while a user is not logged in.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--luks-cipher=</option><replaceable>CIPHER</replaceable></term>
<term><option>--luks-cipher-mode=</option><replaceable>MODE</replaceable></term>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>useradd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
--- /dev/null
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="homed.conf" conditional='ENABLE_RESOLVE'
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>homed.conf</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>homed.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>homed.conf</refname>
+ <refname>homed.conf.d</refname>
+ <refpurpose>Home area/user account manager configuration files</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>/etc/systemd/homed.conf</filename></para>
+ <para><filename>/etc/systemd/homed.conf.d/*.conf</filename></para>
+ <para><filename>/run/systemd/homed.conf.d/*.conf</filename></para>
+ <para><filename>/usr/lib/systemd/homed.conf.d/*.conf</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>These configuration files control default parameters for home areas/user accounts created and
+ managed by
+ <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+ </refsect1>
+
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>The following options are available in the <literal>[Home]</literal> section:</para>
+
+ <variablelist class='home-directives'>
+
+ <varlistentry>
+ <term><varname>DefaultStorage=</varname></term>
+ <listitem><para>The default storage to use for home areas. Takes one of <literal>luks</literal>,
+ <literal>fscrypt</literal>, <literal>directory</literal>, <literal>subvolume</literal>,
+ <literal>cifs</literal>. For details about these options, see
+ <citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If not
+ configured or assigned the empty string, the default storage is automatically determined: if not
+ running in a container enviroment and <filename>/home/</filename> is not itself encrypted, defaults
+ to <literal>luks</literal>. Otherwise defaults to <literal>subvolume</literal> if
+ <filename>/home/</filename> is on a btrfs file system, and <literal>directory</literal>
+ otherwise. Note that the storage selected on the <command>homectl</command> command line always takes
+ precedence.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>DefaultFileSystemType=</varname></term>
+ <listitem><para>When using <literal>luks</literal> as storage (see above), selects the default file
+ system to use inside the user's LUKS volume. Takes one of <literal>ext4</literal>,
+ <literal>xfs</literal> or <literal>btrfs</literal>. If not specified defaults to
+ <literal>ext4</literal>. This setting has no effect if a different storage mechanism is used. The
+ file system type selected on the <command>homectl</command> command line always takes
+ precedence.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
<para>Use
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- to initialize the system host name for mounted (but not booted)
+ to initialize the system hostname for mounted (but not booted)
system images.</para>
</refsect1>
simplified in regards to the character set used before the latter are updated. This is done by removing special
characters and spaces. This ensures that the pretty and the static hostname are always closely related while
still following the validity rules of the specific name. This simplification of the hostname string is not done
- if only the transient and/or static host names are set, and the pretty host name is left untouched.</para>
+ if only the transient and/or static hostnames are set, and the pretty hostname is left untouched.</para>
<para>Pass the empty string <literal></literal> as the
hostname to reset the selected hostnames to their default
<option>cat</option>
</term>
<listitem>
- <para>generates a very terse output, only showing the
- actual message of each journal entry with no metadata,
- not even a timestamp.</para>
+ <para>generates a very terse output, only showing the actual message of each journal entry
+ with no metadata, not even a timestamp. If combined with the
+ <option>--output-fields=</option> option will output the listed fields for each log record,
+ instead of the message.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--output-fields=</option></term>
- <listitem><para>A comma separated list of the fields which should be included in the output. This has an
- effect only for the output modes which would normally show all fields (<option>verbose</option>,
- <option>export</option>, <option>json</option>, <option>json-pretty</option>, <option>json-sse</option> and
- <option>json-seq</option>). The <literal>__CURSOR</literal>, <literal>__REALTIME_TIMESTAMP</literal>,
+ <listitem><para>A comma separated list of the fields which should be included in the output. This has
+ an effect only for the output modes which would normally show all fields (<option>verbose</option>,
+ <option>export</option>, <option>json</option>, <option>json-pretty</option>,
+ <option>json-sse</option> and <option>json-seq</option>), as well as on <option>cat</option>. For the
+ former, the <literal>__CURSOR</literal>, <literal>__REALTIME_TIMESTAMP</literal>,
<literal>__MONOTONIC_TIMESTAMP</literal>, and <literal>_BOOT_ID</literal> fields are always
printed.</para></listitem>
</varlistentry>
<listitem><para>Takes a boolean argument, defaults to on. If off,
<citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- will not query the user for basic system settings, even if the system boots up for the first time and the
- relevant settings are not initialized yet.</para></listitem>
+ will not query the user for basic system settings, even if the system boots up for the first time and
+ the relevant settings are not initialized yet. Not to be confused with
+ <varname>systemd.condition-first-boot=</varname> (see below), which overrides the result of the
+ <varname>ConditionFirstBoot=</varname> unit file condition, and thus controls more than just
+ <filename>systemd-firstboot.service</filename> behaviour.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.condition-needs-update=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If specified, overrides the result of
+ <varname>ConditionNeedsUpdate=</varname> unit condition checks. See
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.condition-first-boot=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If specified, overrides the result of
+ <varname>ConditionFirstBoot=</varname> unit condition checks. See
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details. Not to be confused with <varname>systemd.firstboot=</varname> which only controls behaviour
+ of the <filename>systemd-firstboot.service</filename> system service but has no effect on the
+ condition check (see above).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.clock-usec=</varname></term>
+
+ <listitem><para>Takes a decimal, numeric timestamp in µs since January 1st 1970, 00:00am, to set the
+ system clock to. The system time is set to the specified timestamp early during
+ boot. It is not propagated to the hardware clock (RTC).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>systemd.hostname=</varname></term>
+
+ <listitem><para>Accepts a hostname to set during early boot. If specified takes precedence over what
+ is set in <filename>/etc/hostname</filename>. Note that this does not bar later runtime changes to
+ the hostname, it simply controls the initial hostname set during early boot.</para></listitem>
</varlistentry>
</variablelist>
<literal>Lennart's Computer</literal> an Internet hostname of
<literal>lennarts-computer</literal> might be a good choice.
If this parameter is not set, an application should fall back
- to the Internet host name for presentation
+ to the Internet hostname for presentation
purposes.</para></listitem>
</varlistentry>
</itemizedlist>
<para>Machines are identified by names that follow the same rules
- as UNIX and DNS host names. For details, see below.</para>
+ as UNIX and DNS hostnames. For details, see below.</para>
<para>Machines are instantiated from disk or file system images that
frequently — but not necessarily — carry the same name as machines running
image is optimized for file systems that support copy-on-write, and might not be efficient on others, due to
file system limitations.</para>
- <para>Note that this command leaves host name, machine ID and
+ <para>Note that this command leaves hostname, machine ID and
all other settings that could identify the instance
unmodified. The original image and the cloned copy will hence
share these credentials, and it might be necessary to manually
<para>The <command>machinectl</command> tool operates on machines
and images whose names must be chosen following strict
- rules. Machine names must be suitable for use as host names
+ rules. Machine names must be suitable for use as hostnames
following a conservative subset of DNS and UNIX/Linux
semantics. Specifically, they must consist of one or more
non-empty label strings, separated by dots. No leading or trailing
man_pages = []
html_pages = []
source_xml_files = []
+dbus_docs = []
foreach tuple : xsltproc.found() ? manpages : []
stem = tuple[0]
section = tuple[1]
install_dir : join_paths(docdir, 'html'))
html_pages += p3
- source_xml_files += files(tuple[0] + '.xml')
+ file = files(tuple[0] + '.xml')
+ source_xml_files += file
+ if tuple[0].startswith('org.freedesktop.')
+ dbus_docs += file
+ endif
else
message('Skipping @0@.@1@ because @2@ is false'.format(stem, section, condition))
endif
systemd_directives_xml = custom_target(
'systemd.directives.xml',
- input : source_xml_files,
+ input : ['directives-template.xml', source_xml_files],
output : 'systemd.directives.xml',
- command : [make_directive_index_py, '@OUTPUT@'] + source_xml_files)
+ command : [make_directive_index_py, '@OUTPUT@', '@INPUT@'])
nonindex_xml_files = source_xml_files + [systemd_directives_xml]
systemd_index_xml = custom_target(
############################################################
+if dbus_docs.length() > 0
+ custom_target(
+ 'update-dbus-docs',
+ output : 'update-dbus-docs',
+ command : ['python3',
+ '@0@/tools/update-dbus-docs.py'.format(project_source_root),
+ '--build-dir=@0@'.format(project_build_root),
+ '@INPUT@'],
+ input : dbus_docs)
+endif
+
+############################################################
+
if git.found()
custom_target(
'update-man-rules',
output : 'update-man-rules',
command : ['sh', '-c',
'cd @0@ && '.format(meson.build_root()) +
- 'python3 @0@/tools/make-man-rules.py $(git ls-files ":/man/*.xml") >t && '.format(project_source_root) +
+ 'python3 @0@/tools/update-man-rules.py $(git ls-files ":/man/*.xml") >t && '.format(project_source_root) +
'mv t @0@/rules/meson.build'.format(meson.current_source_dir())],
depend_files : custom_entities_ent)
endif
<title>Description</title>
<para><command>nss-resolve</command> is a plug-in module for the GNU Name Service Switch (NSS) functionality of the
- GNU C Library (<command>glibc</command>) enabling it to resolve host names via the
+ GNU C Library (<command>glibc</command>) enabling it to resolve hostnames via the
<citerefentry><refentrytitle>systemd-resolved</refentrytitle><manvolnum>8</manvolnum></citerefentry> local network
name resolution service. It replaces the <command>nss-dns</command> plug-in module that traditionally resolves
hostnames via DNS.</para>
--- /dev/null
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" >
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="org.freedesktop.LogControl1"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>org.freedesktop.LogControl1</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>org.freedesktop.LogControl1</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>org.freedesktop.LogControl1</refname>
+ <refpurpose>D-Bus interface to query and set logging configuration</refpurpose>
+ </refnamediv>
+
+ <refsect1>
+ <title>Introduction</title>
+
+ <para><interfacename>org.freedesktop.LogControl1</interfacename> is a generic interface that is intended
+ to be used by any daemon which should allow setting the log level and target over D-Bus. It is implemented
+ by various daemons that are part of the
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> suite.</para>
+
+ <para>It is assumed that those settings are global for the whole program, so a fixed object path is
+ used. The interface should always be available under the path
+ <filename>/org/freedesktop/LogControl1</filename>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>The following interface is exposed:</para>
+
+ <programlisting executable="systemd" node="/org/freedesktop/LogControl1" interface="org.freedesktop.LogControl1">
+node /org/freedesktop/LogControl1 {
+ interface org.freedesktop.LogControl1 {
+ properties:
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ @org.freedesktop.systemd1.Privileged("true")
+ readwrite s LogLevel = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ @org.freedesktop.systemd1.Privileged("true")
+ readwrite s LogTarget = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly s SyslogIdentifier = '...';
+ };
+ interface org.freedesktop.DBus.Peer { ... };
+ interface org.freedesktop.DBus.Introspectable { ... };
+ interface org.freedesktop.DBus.Properties { ... };
+};
+ </programlisting>
+
+ <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.LogControl1"/>
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.LogControl1"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="LogLevel"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="LogTarget"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="SyslogIdentifier"/>
+
+ <!--End of Autogenerated section-->
+
+ <refsect2>
+ <title>Properties</title>
+
+ <para><varname>LogLevel</varname> describes the
+ <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>-style
+ log-level, and should be one of <literal>emerg</literal>, <literal>alert</literal>,
+ <literal>crit</literal>, <literal>err</literal>, <literal>warning</literal>, <literal>notice</literal>,
+ <literal>info</literal>, <literal>debug</literal>, in order of increasing verbosity.</para>
+
+ <para><varname>LogTarget</varname> describes the log target (mechanism). It should be one of
+ <literal>console</literal> (log to the console or standard output),
+ <literal>kmsg</literal> (log to the kernel ring buffer),
+ <literal>journal</literal> (log the the journal natively, see
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>),
+ <literal>syslog</literal> (log using the
+ <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> call).
+ </para>
+
+ <para>Those two properties are writable, so they may be set by sufficiently privileged users.</para>
+
+ <para><varname>SyslogIdentifier</varname> is a read-only property that shows the "syslog identifier".
+ It is a short string that identifies the program that is the source of log messages that is passed to
+ the <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> call.
+ </para>
+
+ <para>Note: <command>journalctl</command> option <option>-p</option>/<option>--priority=</option> may
+ be used to filter log messages by log level, option <option>-t</option>/<option>--identifier=</option>
+ may be used to by the syslog identifier, and filters like <literal>_TRANSPORT=syslog</literal>,
+ <literal>_TRANSPORT=journal</literal>, and <literal>_TRANSPORT=kernel</literal> may be used to filter
+ messages by the mechanism through which they reached <command>systemd-journald</command>.</para>
+ </refsect2>
+ </refsect1>
+</refentry>
--- /dev/null
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" >
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="org.freedesktop.home1" conditional='ENABLE_HOMED'
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>org.freedesktop.home1</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>org.freedesktop.home1</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>org.freedesktop.home1</refname>
+ <refpurpose>The D-Bus interface of systemd-homed</refpurpose>
+ </refnamediv>
+
+ <refsect1>
+ <title>Introduction</title>
+
+ <para><citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ is a system service which may be used to to create, remove, change or inspect home areas. This page
+ describes the D-Bus interface.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>The Manager Object</title>
+
+ <para>The service exposes the following interfaces on the Manager object on the bus:</para>
+
+ <programlisting executable="systemd-homed" node="/org/freedesktop/home1" interface="org.freedesktop.home1.Manager">
+node /org/freedesktop/home1 {
+ interface org.freedesktop.home1.Manager {
+ methods:
+ GetHomeByName(in s user_name,
+ out u uid,
+ out s home_state,
+ out u gid,
+ out s real_name,
+ out s home_directory,
+ out s shell,
+ out o bus_path);
+ GetHomeByUID(in u uid,
+ out s user_name,
+ out s home_state,
+ out u gid,
+ out s real_name,
+ out s home_directory,
+ out s shell,
+ out o bus_path);
+ GetUserRecordByName(in s user_name,
+ out s user_record,
+ out b incomplete,
+ out o bus_path);
+ GetUserRecordByUID(in u uid,
+ out s user_record,
+ out b incomplete,
+ out o bus_path);
+ ListHomes(out a(susussso) home_areas);
+ ActivateHome(in s user_name,
+ in s secret);
+ DeactivateHome(in s user_name);
+ RegisterHome(in s user_record);
+ UnregisterHome(in s user_name);
+ CreateHome(in s user_record);
+ RealizeHome(in s user_name,
+ in s secret);
+ RemoveHome(in s user_name);
+ FixateHome(in s user_name,
+ in s secret);
+ AuthenticateHome(in s user_name,
+ in s secret);
+ UpdateHome(in s user_record);
+ ResizeHome(in s user_name,
+ in t size,
+ in s secret);
+ ChangePasswordHome(in s user_name,
+ in s new_secret,
+ in s old_secret);
+ LockHome(in s user_name);
+ UnlockHome(in s user_name,
+ in s secret);
+ AcquireHome(in s user_name,
+ in s secret,
+ in b please_suspend,
+ out h send_fd);
+ RefHome(in s user_name,
+ in b please_suspend,
+ out h send_fd);
+ ReleaseHome(in s user_name);
+ LockAllHomes();
+ properties:
+ readonly a(sso) AutoLogin = [...];
+ };
+ interface org.freedesktop.DBus.Peer { ... };
+ interface org.freedesktop.DBus.Introspectable { ... };
+ interface org.freedesktop.DBus.Properties { ... };
+};
+ </programlisting>
+
+ <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Manager"/>
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Manager"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="GetHomeByName()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="GetHomeByUID()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="GetUserRecordByName()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="GetUserRecordByUID()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ListHomes()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ActivateHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="DeactivateHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="RegisterHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="UnregisterHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="CreateHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="RealizeHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="RemoveHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="FixateHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="AuthenticateHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="UpdateHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ResizeHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ChangePasswordHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="LockHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="UnlockHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="AcquireHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="RefHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ReleaseHome()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="LockAllHomes()"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="AutoLogin"/>
+
+ <!--End of Autogenerated section-->
+
+ <refsect2>
+ <title>Methods</title>
+
+ <para><function>GetHomeByName()</function> returns basic user information (a minimal subset of the full
+ user record), provided a user name. The information supplied more or less matches what
+ <citerefentry><refentrytitle>getpwnam</refentrytitle><manvolnum>3</manvolnum></citerefentry> returns:
+ the numeric UID and GID, the real name, home directory and shell. In addition it returns a state
+ identifier describing the state the user's home directory is in, as well as a bus path referring to the
+ bus object encapsulating the user record and home directory. This object implements the
+ <classname>org.freedesktop.home1.Home</classname> interface documented below.</para>
+
+ <para><function>GetHomeByUID()</function> is similar to <function>GetHomeByName()</function> but
+ acquires the information based on the numeric UID of the user.</para>
+
+ <para><function>GetUserRecordByName()</function> is also similar to
+ <function>GetHomeByName()</function> but returns the full JSON user record data instead of the broken
+ down records. An additional returned boolean indicates whether the record is complete or not. A record
+ is considered complete when its <literal>privileged</literal> section is included, and incomplete if it
+ was removed (see <ulink url="https://systemd.io/USER_RECORD">JSON User Records</ulink> for details
+ about the various sections of a user record). Generally, only privileged clients and clients running
+ under the identity of the user itself get access to the <literal>privileged</literal> section and will
+ thus see complete records.</para>
+
+ <para><function>GetUserRecordByUID()</function> is similar to <function>GetUserRecordByName()</function>
+ but returns the user record matching the specified numeric UID.</para>
+
+ <para><function>ListHomes()</function> returns an array of all locally managed users. The array
+ contains the same fields <function>GetHomeByName()</function> returns: user name, numeric UID, state,
+ numeric GID, real name, home directory, shell and bus path of the matching bus object.</para>
+
+ <para><function>ActivateHome()</function> activates (i.e. mounts) the home directory of the specified
+ user. The second argument shall contain a user record consisting only of a <literal>secret</literal>
+ section (all other sections should be stripped, see <ulink url="https://systemd.io/USER_RECORD">JSON
+ User Records</ulink> for details), and should contain only the secret credentials necessary for
+ unlocking the home directory. Typically a client would invoke this function first with an entirely
+ empty record (which is possibly sufficient if single-factor authentication with a plugged-in security
+ token is configured), and would then retry with a record populated with more information, depending on
+ the returned error code, in case more credentials are necessary. This function is synchronous and
+ returns only after the home directory was fully activated (or the operation failed), which might take
+ some time. Clients must be prepared for that, and typically should extend the D-Bus method call
+ time-out accordingly. This method is equivalent to the <function>Activate()</function> method on the
+ <classname>org.freedesktop.home1.Home</classname> interface documented below, but may be called on the
+ manager object and takes a user name as additional argument, instead.</para>
+
+ <para><function>DeactivateHome()</function> deactivates (i.e. unmounts) the home directory of the
+ specified user. It is equivalent to the <function>Deactivate()</function> method on the
+ <classname>org.freedesktop.home1.Home</classname> interface documented below.</para>
+
+ <para><function>RegisterHome()</function> registers a new home directory locally. It receives the JSON
+ user record as only argument (which typically excludes the <literal>secret</literal>
+ section). Registering a home directory just makes the user record known to the system, it does not
+ create a home directory or such (which is expected to exist already, or created later). This operation
+ is useful to register home directories locally that are not located where
+ <filename>systemd-homed.service</filename> would find them automatically.</para>
+
+ <para><function>UnregisterHome()</function> unregisters an existing home directory. It takes a user
+ name as argument and undoes what <function>RegisterHome()</function> does. It does not attempt to
+ remove the home directory itself, it just unregisters it with the local system. Note that if the home
+ directory is placed where <filename>systemd-homed.service</filename> looks for home directories anyway
+ this call will only undo fixation (see below), but the record will remain known to
+ <filename>systemd-homed.service</filename> and be listed among known records. Since the user record is
+ embedded into the home directory this operation generally does not discard data belonging to the user
+ or their record. This method is equivalent to
+ <function>Unregister()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>CreateHome()</function> registers and creates a new home directory. This takes a fully
+ specified JSON user record as argument (including the <literal>secret</literal> section. This registers
+ the user record locally and creates a home directory matching it, depending on the settings specified
+ in the record in combination with local configuration.</para>
+
+ <para><function>RealizeHome()</function> creates a home directory whose user record is already
+ registered locally. This takes a user name plus a user record consisting only of the
+ <literal>secret</literal> section. Invoking <function>RegisterHome()</function> followed by
+ <function>RealizeHome()</function> is mostly equivalent to calling <function>CreateHome()</function>,
+ except that the latter combines the two in atomic fashion. This method is equivalent to
+ <function>Realize()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>RemoveHome()</function> unregisters a user record locally, and removes the home
+ directory belonging to it, if it is accessible. It takes a user name as argument. This method is equivalent to
+ <function>Remove()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>FixateHome()</function> <literal>fixates</literal> an automatically discovered home
+ directory. <filename>systemd-homed.service</filename> automatically discovers home directories dropped
+ in our plugged in and adds them to the runtime list of user records it manages. A user record
+ discovered that way may be <literal>fixated</literal>, in which case it is copied out of the home
+ directory, onto persistent storage, to fixate the UID/GID assignment of the record, and extract
+ additional (typically previously encrypted) user record data from the home directory. A home directory
+ mus be fixated before it can be logged into. This method call takes a user name and a JSON user record
+ consisting only of the <literal>secret</literal> section as argument. This method is equivalent to
+ <function>Fixate()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+ <para><function>AuthenticateHome()</function> checks passwords or other authentication credentials
+ associated with the home directory. It takes a user name and a JSON user record consisting only of the
+ <literal>secret</literal> section as argument. Note that many of the other method calls authenticate
+ the user first, in order to execute some other operation. This method call only authenticates and
+ executes no further operation. Like <function>ActivateHome()</function> it is usually first invoked
+ with an empty JSON user record, which is then populated for subsequent tries with additional
+ authentication data supplied. This method is equivalent to
+ <function>Authenticate()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>UpdateHome()</function> updates a locally registered user record. Takes a fully
+ specified JSON user record as argument (including the <literal>secret</literal> section). A user with a
+ matching name and realm must be registered locally already, and the last change timestamp of the newly
+ supplied record must be newer than the previously existing user record. Note this operation updates the
+ user record only, it does not propagate passwords/authentication tokens from the user record to the
+ storage back-end, or resizes the storage back-end. Typically a home directory is first updated, and then
+ the password of the underlying storage updated using <function>ChangePasswordHome()</function> as well
+ as the storage resized using <function>ResizeHome()</function>. This method is equivalent to
+ <function>Update()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+ <para><function>ResizeHome()</function> resizes the storage associated with a user record. Takes a user
+ name, a disk size in bytes and a user record consisting only of the <literal>secret</literal> section
+ as argument. If the size is specified as <constant>UINT64_MAX</constant> the storage is resized to the
+ size already specified in the user record. Typically, if the user record is updated using
+ <function>UpdateHome()</function> above this is used to propagate the size configured there-in down to
+ the underlying storage back-end. This method is equivalent to
+ <function>Resize()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>ChangePasswordHome()</function> changes the passwords/authentication tokens of a home
+ directory. Takes a user name, and two JSON user record objects, each consisting only of the
+ <literal>secret</literal> section, for the old and for the new passwords/authentication tokens. If the
+ user record with the new passwords/authentication token data is specified as empty the existing user
+ record's settings are propagated down to the home directory storage. This is typically used after a
+ user record is updated using <function>UpdateHome()</function> in order to propagate the
+ secrets/authentication tokens down to the storage. This method is equivalent to
+ <function>ChangePassword()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>LockHome()</function> temporarily suspends access to a home directory, flushing out any
+ cryptographic keys from memory. This is only supported on some back-ends, and usually done during system
+ suspend, in order to effectively secure home directories while the system is sleeping. Takes a user
+ name as single argument. If an application attempts to access a home directory while it is locked it
+ will typically freeze until the home directory is unlocked again. This method is equivalent to
+ <function>Lock()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+ <para><function>UnlockHome()</function> undoes the effect of <function>LockHome()</function>. Takes a
+ user name and a user record consisting only of the <literal>secret</literal> section as arguments. This
+ method is equivalent to <function>Unlock()</function> on the
+ <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+ <para><function>AcquireHome()</function> activates or unlocks a home directory in a reference counted
+ mode of operation. Takes a user name and user record consisting only of <literal>secret</literal>
+ section as argument. If the home directory is not active yet, it is activated. If it is currently
+ locked it is unlocked. After completion a reference to the activation/unlocking of the home directory
+ is returned via a file descriptor. When the last client which acquired such a file descriptor closes it
+ the home directory is automatically deactivated again. This method is typically invoked when a user
+ logs in, and the file descriptor is held until the user logs out again, thus ensuring the user's home
+ directory can be unmounted automatically again in a robust fashion, when the user logs out. The third
+ argument is a boolean which indicates whether the client invoking the call is able to automatically
+ re-authenticate when the system comes back from suspending. It should be set by all clients that
+ implement a secure lock screen running outside of the user's context, that is brought up when the
+ system comes back from suspend and can be used to re-acquire the credentials to unlock the user's home
+ directory. If a home directory has at least one client with an open reference to the home directory
+ that does not support this it is not suspended automatically at system suspend, otherwise it is. This
+ method is equivalent to <function>Acquire()</function> on the
+ <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+ <para><function>RefHome()</function> is similar to <function>AcquireHome()</function> but takes no user
+ record with <literal>secret</literal> section, i.e. will take an additional reference to an already
+ activated/unlocked home directory without attempting to activate/unlock it itself. It will fail if the
+ home directory is not already activated. This method is equivalent to
+ <function>Ref()</function> on the <classname>org.freedesktop.home1.Home</classname>
+ interface.</para>
+
+ <para><function>ReleaseHome()</function> releases a home directory again, if all file descriptors
+ referencing it are already closed, that where acquired through <function>AcquireHome()</function> or
+ <function>RefHome()</function>. Note that this call does not actually cause the deactivation of the
+ home directory (which happens automatically when the last referencing file descriptor is closed), but
+ is simply a synchronization mechanism that allows delaying of the user session's termination until any
+ triggered deactivation is completed. This method is equivalent to <function>Release()</function> on the
+ <classname>org.freedesktop.home1.Home</classname> interface.</para>
+
+ <para><function>LockAllHomes()</function> locks all active home directories that only have references
+ that opted into automatic suspending during system suspend. This is usually invoked automatically
+ shortly before system suspend.</para>
+ </refsect2>
+
+ <refsect2>
+ <title>Properties</title>
+
+ <para><varname>AutoLogin</varname> exposes an array of structures consisting of user name, seat name
+ and object path of an home directory object. All locally managed users that have the
+ <literal>autoLogin</literal> field set are listed here, with the seat name they are associated with. A
+ display manager may watch this property and pre-fill the login screen with the users exposed this
+ way.</para>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>The Home Object</title>
+
+ <programlisting executable="systemd-homed" node="/org/freedesktop/home1/home" interface="org.freedesktop.home1.Home">
+node /org/freedesktop/home1/home {
+ interface org.freedesktop.home1.Home {
+ methods:
+ Activate(in s secret);
+ Deactivate();
+ Unregister();
+ Realize(in s secret);
+ Remove();
+ Fixate(in s secret);
+ Authenticate(in s secret);
+ Update(in s user_record);
+ Resize(in t size,
+ in s secret);
+ ChangePassword(in s new_secret,
+ in s old_secret);
+ Lock();
+ Unlock(in s secret);
+ Acquire(in s secret,
+ in b please_suspend,
+ out h send_fd);
+ Ref(in b please_suspend,
+ out h send_fd);
+ Release();
+ properties:
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly s UserName = '...';
+ readonly u UID = ...;
+ readonly (suusss) UnixRecord = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
+ readonly s State = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("invalidates")
+ readonly (sb) UserRecord = ...;
+ };
+ interface org.freedesktop.DBus.Peer { ... };
+ interface org.freedesktop.DBus.Introspectable { ... };
+ interface org.freedesktop.DBus.Properties { ... };
+ interface org.freedesktop.DBus.ObjectManager { ... };
+};
+ </programlisting>
+
+ <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.DBus.ObjectManager"/>
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Home"/>
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.DBus.ObjectManager"/>
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.home1.Home"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Activate()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Deactivate()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Unregister()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Realize()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Remove()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Fixate()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Authenticate()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Update()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Resize()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ChangePassword()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Lock()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Unlock()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Acquire()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Ref()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Release()"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="UserName"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="UID"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="UnixRecord"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="State"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="UserRecord"/>
+
+ <!--End of Autogenerated section-->
+
+ <refsect2>
+ <title>Methods</title>
+
+ <para><function>Activate()</function>, <function>Deactivate()</function>,
+ <function>Unregister()</function>, <function>Realize()</function>, <function>Remove()</function>,
+ <function>Fixate()</function>, <function>Authenticate()</function>, <function>Update()</function>,
+ <function>Resize()</function>, <function>ChangePassword()</function>, <function>Lock()</function>,
+ <function>Unlock()</function>, <function>Acquire()</function>, <function>Ref()</function>,
+ <function>Release()</function> operate like their matching counterparts on the
+ <classname>org.freedesktop.home1.Manager</classname> interface (see above). The main difference is that
+ they are methods of the home directory objects, and hence carry no additional user name
+ parameter. Which of the two flavors of methods to call depends on the handles to the user known on the
+ client side: if only the user name is known, it's preferable to use the methods on the manager object
+ since they operate with user names only. If however the home object path was already acquired some way
+ it is preferable to operate on the <classname>org.freedesktop.home1.Home</classname> objects
+ instead.</para>
+ </refsect2>
+
+ <refsect2>
+ <title>Properties</title>
+
+ <para><varname>UserName</varname> contains the user name of the user account/home directory.</para>
+
+ <para><varname>UID</varname> contains the numeric UNIX UID of the user account.</para>
+
+ <para><varname>UnixRecord</varname> contains a structure encapsulating the six fields a
+ <structname>struct passwd</structname> typically contains (the password field is suppressed).</para>
+
+ <para><varname>State</varname> exposes the current state home the home directory.</para>
+
+ <para><varname>UserRecord</varname> contains the full JSON user record string of the user account.</para>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>Versioning</title>
+
+ <para>These D-Bus interfaces follow <ulink url="http://0pointer.de/blog/projects/versioning-dbus.html">
+ the usual interface versioning guidelines</ulink>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
<para>The service exposes the following interfaces on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.hostname1 \
- --object-path /org/freedesktop/hostname1
-
+ <programlisting executable="systemd-hostnamed" node="/org/freedesktop/hostname1" interface="org.freedesktop.hostname1">
node /org/freedesktop/hostname1 {
interface org.freedesktop.hostname1 {
methods:
};
</programlisting>
- <!--method SetDeployment is not documented!-->
-
- <!--method SetLocation is not documented!-->
-
- <!--method GetProductUUID is not documented!-->
-
- <!--property Hostname is not documented!-->
-
- <!--property StaticHostname is not documented!-->
-
- <!--property PrettyHostname is not documented!-->
-
- <!--property IconName is not documented!-->
-
- <!--property Chassis is not documented!-->
-
- <!--property Deployment is not documented!-->
-
- <!--property Location is not documented!-->
-
- <!--property KernelName is not documented!-->
-
- <!--property KernelRelease is not documented!-->
-
- <!--property KernelVersion is not documented!-->
-
- <!--property OperatingSystemPrettyName is not documented!-->
-
- <!--property OperatingSystemCPEName is not documented!-->
-
- <!--property HomeURL is not documented!-->
-
<!--Autogenerated cross-references for systemd.directives, do not edit-->
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.hostname1"/>
<para>Whenever the hostname or other metadata is changed via the daemon,
<function>PropertyChanged</function> signals are sent out to subscribed clients. Changing a hostname
- using this interface is authenticated via PolicyKit.</para>
+ using this interface is authenticated via
+ <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>.</para>
</refsect1>
<refsect1>
it could not be auto-detected. Set this property to the empty string to reenable the automatic detection of
the chassis type from firmware information.</para>
- <para>A client that wants to change the local hostname for DHCP/mDNS should invoke
- <code>SetHostname("newname", false)</code> as soon as the name is available and afterwards reset it via
- <code>SetHostname("")</code>.</para>
-
<para>Note that <filename>systemd-hostnamed</filename> starts only on request and terminates after a
short idle period. This effectively means that <function>PropertyChanged</function> messages are not sent
out for changes made directly on the files (as in: administrator edits the files with vi). This is
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for that. For more information on these files and syscalls see the respective man pages.</para>
- <para>The <varname>user_interaction</varname> boolean parameters can be used to control whether PolicyKit
- should interactively ask the user for authentication credentials if required.</para>
+ <refsect2>
+ <title>Methods and Properties</title>
+
+ <para><function>SetHostname()</function> sets the transient (dynamic) hostname which is exposed by the
+ <varname>Hostname</varname> property. If empty, the transient hostname is set to the static hostname.
+ </para>
+
+ <para><function>SetStaticHostname()</function> sets the static hostname which is exposed by the
+ <varname>StaticHostname</varname> property. If empty, the built-in default of
+ <literal>&FALLBACK_HOSTNAME;</literal> is used.</para>
+
+ <para><function>SetPrettyHostname()</function> sets the pretty hostname which is exposed by the
+ <varname>PrettyHostname</varname> property.</para>
+
+ <para><function>SetIconName()</function>, <function>SetChassis()</function>,
+ <function>SetDeployment()</function>, and <function>SetLocation()</function> set the properties
+ <varname>IconName</varname> (the name of the icon representing for the machine),
+ <varname>Chassis</varname> (the machine form factor), <varname>Deployment</varname> (the system
+ deployment environment), and <varname>Location</varname> (physical system location), respectively.
+ </para>
+
+ <para><varname>PrettyHostname</varname>, <varname>IconName</varname>, <varname>Chassis</varname>,
+ <varname>Deployment</varname>, and <varname>Location</varname> are stored in
+ <filename>/etc/machine-info</filename>. See
+ <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ the semantics of those settings.</para>
+
+ <para><function>GetProductUUID()</function> returns the "product uuid" as exposed by the kernel based
+ on DMI information in <filename>/sys/class/dmi/id/product_uuid</filename>. Reading the file directly
+ requires root privileges, and this method allows access to unprivileged clients through the polkit
+ framework.</para>
+
+ <para><varname>KernelName</varname>, <varname>KernelRelease</varname>, and
+ <varname>KernelVersion</varname> expose the kernel name (e.g. <literal>Linux</literal>), release
+ (e.g. <literal>5.0.0-11</literal>, and version (i.e. the build number, e.g. <literal>#11</literal>) as
+ reported by
+ <citerefentry project="man-pages"><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+ <varname>OperatingSystemPrettyName</varname>, <varname>OperatingSystemCPEName</varname>, and
+ <varname>HomeURL</varname> expose the <varname>PRETTY_NAME=</varname>, <varname>CPE_NAME=</varname> and
+ <varname>HOME_URL=</varname> fields from
+ <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>. The
+ purpose of those properties is to allow remote clients to access this information over D-Bus. Local
+ clients can access the information directly.</para>
+ </refsect2>
+
+ <refsect2>
+ <title>Security</title>
+
+ <para>The <varname>interactive</varname> boolean parameters can be used to control whether polkit
+ should interactively ask the user for authentication credentials if required.</para>
+
+ <para>The polkit action for <function>SetHostname()</function> is
+ <interfacename>org.freedesktop.hostname1.set-hostname</interfacename>. For
+ <function>SetStaticHostname()</function> and <function>SetPrettyHostname()</function> it is
+ <interfacename>org.freedesktop.hostname1.set-static-hostname</interfacename>. For
+ <function>SetIconName()</function> and <function>SetChassis()</function> it is
+ <interfacename>org.freedesktop.hostname1.set-machine-info</interfacename>.</para>
+ </refsect2>
+ </refsect1>
- <para>The PolicyKit action for <function>SetHostname()</function> is
- <interfacename>org.freedesktop.hostname1.set-hostname</interfacename>. For
- <function>SetStaticHostname()</function> and <function>SetPrettyHostname()</function> it is
- <interfacename>org.freedesktop.hostname1.set-static-hostname</interfacename>. For
- <function>SetIconName()</function> and <function>SetChassis()</function> it is
- <interfacename>org.freedesktop.hostname1.set-machine-info</interfacename>.</para>
+ <refsect1>
+ <title>Recommendations</title>
- <para>Here are three examples show how the pretty hostname and the icon name should be used:
+ <para>Here are three examples that show how the pretty hostname and the icon name should be used:
<itemizedlist>
- <listitem><para>When registering DNS-SD services: use the pretty hostname in the service name, and
- pass the icon name in the TXT data, if there is an icon name. Browsing clients can then show the server
- icon on each service. This is especially useful for WebDAV applications or UPnP media sharing.
+ <listitem><para>When registering DNS-SD services: use the pretty hostname in the service name, and pass
+ the icon name in the TXT data, if there is an icon name. Browsing clients can then show the server icon
+ on each service. This is especially useful for WebDAV applications or UPnP media sharing.
</para></listitem>
<listitem><para>Set the bluetooth name to the pretty hostname.</para></listitem>
- <listitem><para>When your file browser has a "Computer" icon, replace the name with the pretty hostname if set, and the icon with the icon name, if it is set.</para></listitem>
+ <listitem><para>When your file browser has a "Computer" icon, replace the name with the pretty hostname
+ if set, and the icon with the icon name, if it is set.</para></listitem>
</itemizedlist></para>
<para>To properly handle name lookups with changing local hostnames without having to edit
- <filename>/etc/hosts</filename>, we recommend using <filename>systemd-hostnamed</filename> in
- combination with <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <filename>/etc/hosts</filename>, we recommend using <filename>systemd-hostnamed</filename> in combination
+ with <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
+ <para>A client that wants to change the local hostname for DHCP/mDNS should invoke
+ <code>SetHostname("newname", false)</code> as soon as the name is available and afterwards reset it via
+ <code>SetHostname("")</code>.</para>
+
<para>Here are some recommendations to follow when generating a static (internet) hostname from a pretty
name:
<itemizedlist>
</itemizedlist></para>
<para>Of course, an already valid internet hostname label you enter and pass through this
- conversion should stay unmodified, so that users have direct control of it, if they want -- by simply
+ conversion should stay unmodified, so that users have direct control of it, if they want — by simply
ignoring the fact that the pretty hostname is pretty and just edit it as if it was the normal internet
name.</para>
</refsect1>
the usual interface versioning guidelines</ulink>.</para>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.hostname1</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system \
+ --dest org.freedesktop.hostname1 \
+ --object-path /org/freedesktop/hostname1
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>See also</title>
<para>The service exposes the following interfaces on the Manager object on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.import1 \
- --object-path /org/freedesktop/import1
-
+ <programlisting executable="systemd-importd" node="/org/freedesktop/import1" interface="org.freedesktop.import1.Manager">
node /org/freedesktop/import1 {
interface org.freedesktop.import1.Manager {
methods:
<refsect1>
<title>The Transfer Object</title>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.import1 \
- --object-path /org/freedesktop/import1/transfer/_1
-
+ <programlisting executable="systemd-importd" node="/org/freedesktop/import1/transfer/_1" interface="org.freedesktop.import1.Transfer">
node /org/freedesktop/import1/transfer/_1 {
interface org.freedesktop.import1.Transfer {
methods:
</refsect2>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.import1.Manager</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system \
+ --dest org.freedesktop.import1 \
+ --object-path /org/freedesktop/import1
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.import1.Transfer</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system \
+ --dest org.freedesktop.import1 \
+ --object-path /org/freedesktop/import1/transfer/_1
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<para>The service exposes the following interfaces on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.locale1 \
- --object-path /org/freedesktop/locale1
-
+ <programlisting executable="systemd-localed" node="/org/freedesktop/locale1" interface="org.freedesktop.locale1">
node /org/freedesktop/locale1 {
interface org.freedesktop.locale1 {
methods:
<para>Use the empty string for the keymap parameters you wish not to set.</para>
- <para>The <varname>interactive</varname> boolean parameters can be used to control whether PolicyKit
+ <para>The <varname>interactive</varname> boolean parameters can be used to control whether
+ <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
should interactively ask the user for authentication credentials if required.</para>
</refsect2>
<refsect2>
<title>Security</title>
- <para>Changing the system locale or keymap using this interface is authenticated via PolicyKit. The
- PolicyKit action for <function>SetLocale()</function> is
- <constant>org.freedesktop.locale1.set-locale</constant>. The PolicyKit action for
+ <para>Changing the system locale or keymap using this interface is authenticated via polkit. The
+ polkit action for <function>SetLocale()</function> is
+ <constant>org.freedesktop.locale1.set-locale</constant>. The polkit action for
<function>SetX11Keyboard()</function> and <function>SetVConsoleKeyboard()</function> is
<constant>org.freedesktop.locale1.set-keyboard</constant>.</para>
</refsect2>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.locale1</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.locale1 \
+ --object-path /org/freedesktop/locale1
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<para>The service exposes the following interfaces on the Manager object on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.login1 \
- --object-path /org/freedesktop/login1
-
+ <programlisting executable="systemd-logind" node="/org/freedesktop/login1" interface="org.freedesktop.login1.Manager">
node /org/freedesktop/login1 {
interface org.freedesktop.login1.Manager {
methods:
and seat are identified by their respective IDs.</para>
<para><function>SetUserLinger()</function> enables or disables user lingering. If enabled, the runtime
- directory of a user is kept around and he may continue to run processes while he is logged out. If
+ directory of a user is kept around and they may continue to run processes while logged out. If
disabled, the runtime directory goes away as soon as they log out. <function>SetUserLinger()</function>
expects three arguments: the UID, a boolean whether to enable/disable and a boolean controlling the
- PolicyKit authorization interactivity (see below). Note that the user linger state is persistently
+ <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
+ authorization interactivity (see below). Note that the user linger state is persistently
stored on disk.</para>
<para><function>AttachDevice()</function> may be used to assign a specific device to a specific
- seat. The device is identified by its /sys path and must be eligible for seat assignments. <function>AttachDevice()</function> takes three
- arguments: the seat id, the sysfs path, and a boolean for controlling PolicyKit interactivity (see
- below). Device assignments are persistently stored on disk. To create a new seat, simply specify a
- previously unused seat id. For more information about the seat assignment logic see
+ seat. The device is identified by its <filename>/sys</filename> path and must be eligible for seat
+ assignments. <function>AttachDevice()</function> takes three arguments: the seat id, the sysfs path,
+ and a boolean for controlling polkit interactivity (see below). Device assignments are persistently
+ stored on disk. To create a new seat, simply specify a previously unused seat id. For more information
+ about the seat assignment logic see
<ulink url="https://www.freedesktop.org/wiki/Software/systemd/multiseat">Multi-Seat for Linux</ulink>.
</para>
<para><function>FlushDevices()</function> removes all explicit seat assignments for devices, resetting
- all assignments to the automatic defaults. The only argument it takes is the PolicyKit interactivity
+ all assignments to the automatic defaults. The only argument it takes is the polkit interactivity
boolean (see below).</para>
<para><function>PowerOff()</function>, <function>Reboot()</function>, <function>Halt()</function>,
the machine is powered down). <function>HybridSleep()</function> results in the system entering a
hybrid-sleep mode, i.e. the system is both hibernated and suspended.
<function>SuspendThenHibernate()</function> results in the system being suspended, then later woken
- using an RTC timer and hibernated. The only argument is the PolicyKit interactivity boolean
+ using an RTC timer and hibernated. The only argument is the polkit interactivity boolean
<varname>interactive</varname> (see below). The main purpose of these calls is that they enforce
- PolicyKit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged
+ polkit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged
users. They also enforce inhibition locks. UIs should expose these calls as the primary mechanism to
poweroff/reboot/suspend/hibernate the machine.</para>
<refsect2>
<title>Security</title>
- <para>A number of operations are protected via the PolicyKit privilege
+ <para>A number of operations are protected via the polkit privilege
system. <function>SetUserLinger()</function> requires the
<interfacename>org.freedesktop.login1.set-user-linger</interfacename>
privilege. <function>AttachDevice()</function> requires
<interfacename>org.freedesktop.login1.inhibit-handle-lid-switch</interfacename> depending on the lock
type and mode taken.</para>
- <para>The <varname>interactive</varname> boolean parameters can be used to control whether PolicyKit
+ <para>The <varname>interactive</varname> boolean parameters can be used to control whether polkit
should interactively ask the user for authentication credentials if required.</para>
</refsect2>
</refsect1>
<refsect1>
<title>Seat Objects</title>
- <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.login1 \
- --object-path /org/freedesktop/login1/seat/seat0
-
+ <programlisting executable="systemd-logind" node="/org/freedesktop/login1/seat/seat0" interface="org.freedesktop.login1.Seat">
node /org/freedesktop/login1/seat/seat0 {
interface org.freedesktop.login1.Seat {
methods:
readonly s Id = '...';
readonly (so) ActiveSession = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
- readonly b CanMultiSession = ...;
- @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b CanTTY = ...;
readonly b CanGraphical = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
<variablelist class="dbus-property" generated="True" extra-ref="ActiveSession"/>
- <variablelist class="dbus-property" generated="True" extra-ref="CanMultiSession"/>
-
<variablelist class="dbus-property" generated="True" extra-ref="CanTTY"/>
<variablelist class="dbus-property" generated="True" extra-ref="CanGraphical"/>
<title>Signals</title>
<para>Whenever <function>ActiveSession</function>, <function>Sessions</function>,
- <function>CanGraphical</function>, <function>CanMultiSession</function> and <function>CanTTY</function>
+ <function>CanGraphical</function>, <function>CanTTY</function>,
or the idle state changes, <function>PropertyChanged</function> signals are sent out to which clients
can subscribe.</para>
</refsect2>
<para><varname>ActiveSession</varname> encodes the currently active session if there is one. It is a
structure consisting of the session id and the object path.</para>
- <para><varname>CanMultiSession</varname> encodes whether the session is multi-session capable,
- <varname>CanTTY</varname> whether it is suitable for text logins, <varname>CanGraphical</varname>
- whether it is suitable for graphical sessions.</para>
+ <para><varname>CanTTY</varname> encodes whether the session is suitable for text logins, and
+ <varname>CanGraphical</varname> whether it is suitable for graphical sessions.</para>
<para>The <varname>Sessions</varname> property is an array of all current sessions of this seat, each
encoded in a structure consisting of the ID and the object path.</para>
<para>The <varname>IdleHint</varname>, <varname>IdleSinceHint</varname>, and
- <varname>IdleSinceHint</varname> properties encode the idle state, similar to the one exposed on the
- Manager object, but specific for this seat.</para>
+ <varname>IdleSinceHintMonotonic</varname> properties encode the idle state, similar to the ones exposed
+ on the <interfacename>Manager</interfacename> object, but specific for this seat.</para>
</refsect2>
</refsect1>
<refsect1>
<title>User Objects</title>
- <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.login1 \
- --object-path /org/freedesktop/login1/user/_1000
-
+ <programlisting executable="systemd-logind" node="/org/freedesktop/login1/user/_1000" interface="org.freedesktop.login1.User">
node /org/freedesktop/login1/user/_1000 {
interface org.freedesktop.login1.User {
methods:
<refsect1>
<title>Session Objects</title>
- <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.login1 \
- --object-path /org/freedesktop/login1/session/45
-
-node /org/freedesktop/login1/session/45 {
+ <programlisting executable="systemd-logind" node="/org/freedesktop/login1/session/1" interface="org.freedesktop.login1.Session">
+node /org/freedesktop/login1/session/1 {
interface org.freedesktop.login1.Session {
methods:
Terminate();
in i signal_number);
TakeControl(in b force);
ReleaseControl();
+ SetType(in s type);
TakeDevice(in u major,
in u minor,
out h fd,
readonly u Leader = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly u Audit = ...;
- @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Type = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Class = '...';
};
</programlisting>
+ <!--Autogenerated cross-references for systemd.directives, do not edit-->
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.login1.Session"/>
+
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.login1.Session"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Terminate()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Activate()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Lock()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Unlock()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="SetIdleHint()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="SetLockedHint()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Kill()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="TakeControl()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ReleaseControl()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="SetType()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="TakeDevice()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ReleaseDevice()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="PauseDeviceComplete()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="SetBrightness()"/>
+
+ <variablelist class="dbus-signal" generated="True" extra-ref="PauseDevice"/>
+
+ <variablelist class="dbus-signal" generated="True" extra-ref="ResumeDevice"/>
+
+ <variablelist class="dbus-signal" generated="True" extra-ref="Lock"/>
+
+ <variablelist class="dbus-signal" generated="True" extra-ref="Unlock"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Id"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="User"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Name"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Timestamp"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="TimestampMonotonic"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="VTNr"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Seat"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="TTY"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Display"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Remote"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="RemoteHost"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="RemoteUser"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Service"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Desktop"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Scope"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Leader"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Audit"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Type"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Class"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="Active"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="State"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="IdleHint"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="IdleSinceHint"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="IdleSinceHintMonotonic"/>
+
+ <variablelist class="dbus-property" generated="True" extra-ref="LockedHint"/>
+
+ <!--End of Autogenerated section-->
+
<refsect2>
<title>Methods</title>
out and replaced. Otherwise, this method fails if there is already a controller. Note that this method is
limited to D-Bus users with the effective UID set to the user of the session or root.</para>
- <para><function>ReleaseControl()</function> drops control of a given session. Closing the
- D-Bus connection implicitly releases control as well. See <function>TakeControl()</function> for more information. This
- method also releases all devices for which the controller requested ownership via <function>TakeDevice()</function>.
- </para>
+ <para><function>ReleaseControl()</function> drops control of a given session. Closing the D-Bus
+ connection implicitly releases control as well. See <function>TakeControl()</function> for more
+ information. This method also releases all devices for which the controller requested ownership via
+ <function>TakeDevice()</function>.</para>
+
+ <para><function>SetType()</function> allows the type of the session to be changed dynamically. It can
+ only be called by session's current controller. If <function>TakeControl()</function> has not been
+ called, this method will fail. In addition, the session type will be reset to its original value once
+ control is released, either by calling <function>ReleaseControl()</function> or closing the D-Bus
+ connection. This should help prevent a session from entering an inconsistent state, for example if the
+ controller crashes. The only argument <varname>type</varname> is the new session type.</para>
<para><function>TakeDevice()</function> allows a session controller to get a file descriptor for a
specific device. Pass in the major and minor numbers of the character device and
</refsect2>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.login1.Manager</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+ --object-path /org/freedesktop/login1
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.login1.Seat</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+ --object-path /org/freedesktop/login1/seat/seat0
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.login1.User</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+ --object-path /org/freedesktop/login1/user/_1000
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.login1.Session</interfacename> on the bus</title>
+
+ <programlisting>$ gdbus introspect --system --dest org.freedesktop.login1 \
+ --object-path /org/freedesktop/login1/session/45
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<para>The service exposes the following interfaces on the Manager object on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.machine1 \
- --object-path /org/freedesktop/machine1
-
+ <programlisting executable="systemd-machined" node="/org/freedesktop/machine1" interface="org.freedesktop.machine1.Manager">
node /org/freedesktop/machine1 {
interface org.freedesktop.machine1.Manager {
methods:
<refsect1>
<title>Machine Objects</title>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.machine1 \
- --object-path /org/freedesktop/machine1/machine/rawhide
-
+ <programlisting executable="systemd-machined" node="/org/freedesktop/machine1/machine/rawhide" interface="org.freedesktop.machine1.Machine">
node /org/freedesktop/machine1/machine/rawhide {
interface org.freedesktop.machine1.Machine {
methods:
</refsect2>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.machine1.Manager</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.machine1 \
+ --object-path /org/freedesktop/machine1
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.machine1.Machine</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.machine1 \
+ --object-path /org/freedesktop/machine1/machine/rawhide
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<para>The service exposes the following interfaces on the Manager object on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.resolve1 \
- --object-path /org/freedesktop/resolve1
-
+ <programlisting executable="systemd-resolved" node="/org/freedesktop/resolve1" interface="org.freedesktop.resolve1.Manager">
node /org/freedesktop/resolve1 {
interface org.freedesktop.resolve1.Manager {
methods:
in s type,
in q service_port,
in q service_priority,
- in q serwise_weight,
+ in q service_weight,
in aa{say} txt_datas,
out o service_path);
UnregisterService(in o service_path);
readonly as DNSSECNegativeTrustAnchors = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s DNSStubListener = '...';
- @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
- @org.freedesktop.systemd1.Privileged("true")
- readwrite s LogLevel = '...';
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
<variablelist class="dbus-property" generated="True" extra-ref="DNSStubListener"/>
- <variablelist class="dbus-property" generated="True" extra-ref="LogLevel"/>
-
<!--End of Autogenerated section-->
<refsect2>
default LLMNR setting is used. If <literal>yes</literal>, LLMNR is used for resolution of single-label
names and the local hostname is registered on all local LANs for LLMNR resolution by peers. If
<literal>no</literal>, LLMNR is turned off fully on this interface. If <literal>resolve</literal>, LLMNR
- is only enabled for resolving names, but the local host name is not registered for other peers to
+ is only enabled for resolving names, but the local hostname is not registered for other peers to
use.</para>
<para>Similarly, the <function>SetLinkMulticastDNS()</function> method enables or disables MulticastDNS
<refsect1>
<title>Link Object</title>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.resolve1 \
- --object-path /org/freedesktop/resolve1/link/_34
-
-node /org/freedesktop/resolve1/link/_34 {
+ <programlisting executable="systemd-resolved" node="/org/freedesktop/resolve1/link/_1" interface="org.freedesktop.resolve1.Link">
+node /org/freedesktop/resolve1/link/_1 {
interface org.freedesktop.resolve1.Link {
methods:
SetDNS(in a(iay) addresses);
</variablelist>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.resolve1.Manager</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.resolve1 \
+ --object-path /org/freedesktop/resolve1
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.resolve1.Link</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.resolve1 \
+ --object-path /org/freedesktop/resolve1/link/_11
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<para>Properties exposing time values are usually encoded in microseconds (usec) on the bus, even if
their corresponding settings in the unit files are in seconds.</para>
- <para>In contrast to most of the other services of the systemd suite, PID 1 does not use PolicyKit for
- controlling access to privileged operations, but relies exclusively on the low-level D-Bus policy
- language. (This is done in order to avoid a cyclic dependency between PolicyKit and systemd/PID 1.) This
+ <para>In contrast to most of the other services of the systemd suite, PID 1 does not use
+ <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
+ for controlling access to privileged operations, but relies exclusively on the low-level D-Bus policy
+ language. (This is done in order to avoid a cyclic dependency between polkit and systemd/PID 1.) This
means that sensitive operations exposed by PID 1 on the bus are generally not available to unprivileged
processes directly. However, some operations (such as shutdown/reboot/suspend) are made available through the D-Bus
API of logind, see
<para>The main entry point object is available on the fixed
<constant>/org/freedesktop/systemd1</constant> object path:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1" interface="org.freedesktop.systemd1.Manager">
node /org/freedesktop/systemd1 {
interface org.freedesktop.systemd1.Manager {
methods:
in i signal);
CleanUnit(in s name,
in as mask);
+ FreezeUnit(in s name);
+ ThawUnit(in s name);
ResetFailedUnit(in s name);
SetUnitProperties(in s name,
in b runtime,
<!--method CleanUnit is not documented!-->
+ <!--method FreezeUnit is not documented!-->
+
+ <!--method ThawUnit is not documented!-->
+
<!--method RefUnit is not documented!-->
<!--method UnrefUnit is not documented!-->
<variablelist class="dbus-method" generated="True" extra-ref="CleanUnit()"/>
+ <variablelist class="dbus-method" generated="True" extra-ref="FreezeUnit()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="ThawUnit()"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="ResetFailedUnit()"/>
<variablelist class="dbus-method" generated="True" extra-ref="SetUnitProperties()"/>
<title>Security</title>
<para>Read access is generally granted to all clients. Additionally, for unprivileged clients, some
- operations are allowed through the PolicyKit privilege system. Operations which modify unit state
+ operations are allowed through the polkit privilege system. Operations which modify unit state
(<function>StartUnit()</function>, <function>StopUnit()</function>, <function>KillUnit()</function>,
<function>RestartUnit()</function> and similar, <function>SetProperty</function>) require
<interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
<refsect1>
<title>Unit Objects</title>
- <programlisting interface="org.freedesktop.systemd1.Unit">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice" interface="org.freedesktop.systemd1.Unit">
node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
interface org.freedesktop.systemd1.Unit {
methods:
Ref();
Unref();
Clean(in as mask);
+ Freeze();
+ Thaw();
properties:
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s Id = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s LoadState = '...';
readonly s ActiveState = '...';
+ readonly s FreezerState = '...';
readonly s SubState = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s FragmentPath = '...';
readonly b CanIsolate = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as CanClean = ['...', ...];
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly b CanFreeze = ...;
readonly (uo) Job = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b StopWhenUnneeded = ...;
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
interface org.freedesktop.DBus.Properties { ... };
- interface org.freedesktop.systemd1.Service { ... };
};
</programlisting>
<!--method Clean is not documented!-->
+ <!--method Freeze is not documented!-->
+
+ <!--method Thaw is not documented!-->
+
<!--property PartOf is not documented!-->
<!--property RequisiteOf is not documented!-->
<!--property JoinsNamespaceOf is not documented!-->
+ <!--property FreezerState is not documented!-->
+
<!--property DropInPaths is not documented!-->
<!--property UnitFilePreset is not documented!-->
<!--property CanClean is not documented!-->
+ <!--property CanFreeze is not documented!-->
+
<!--property OnFailureJobMode is not documented!-->
<!--property JobRunningTimeoutUSec is not documented!-->
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-method" generated="True" extra-ref="Start()"/>
<variablelist class="dbus-method" generated="True" extra-ref="Clean()"/>
+ <variablelist class="dbus-method" generated="True" extra-ref="Freeze()"/>
+
+ <variablelist class="dbus-method" generated="True" extra-ref="Thaw()"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Id"/>
<variablelist class="dbus-property" generated="True" extra-ref="Names"/>
<variablelist class="dbus-property" generated="True" extra-ref="ActiveState"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="FreezerState"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="SubState"/>
<variablelist class="dbus-property" generated="True" extra-ref="FragmentPath"/>
<variablelist class="dbus-property" generated="True" extra-ref="CanClean"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="CanFreeze"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Job"/>
<variablelist class="dbus-property" generated="True" extra-ref="StopWhenUnneeded"/>
allowed for everyone. All operations are allowed for clients with the
<constant>CAP_SYS_ADMIN</constant> capability or when the
<interfacename>org.freedesktop.systemd1.manage-units</interfacename> privilege is granted by
- PolicyKit.</para>
+ polkit.</para>
</refsect2>
</refsect1>
<interfacename>org.freedesktop.systemd1.Service</interfacename> interface (described here) in addition to
the generic <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Service">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice" interface="org.freedesktop.systemd1.Service">
node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
interface org.freedesktop.systemd1.Service {
methods:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Service"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
<refsect1>
<title>Socket Unit Objects</title>
- <programlisting interface="org.freedesktop.systemd1.Socket">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket" interface="org.freedesktop.systemd1.Socket">
node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
interface org.freedesktop.systemd1.Socket {
methods:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Socket"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Socket"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Socket"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
<refsect1>
<title>Target Unit Objects</title>
- <programlisting interface="org.freedesktop.systemd1.Target">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/basic_2etarget
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/basic_2etarget" interface="org.freedesktop.systemd1.Target">
node /org/freedesktop/systemd1/unit/basic_2etarget {
interface org.freedesktop.systemd1.Target {
};
<para>All device unit objects implement the <interfacename>org.freedesktop.systemd1.Device</interfacename> interface (described here)
in addition to the generic <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Device">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/dev_2dfoo_2edevice
-
-node /org/freedesktop/systemd1/unit/dev_2dfoo_2edevice {
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/dev_2dttyS0_2edevice" interface="org.freedesktop.systemd1.Device">
+node /org/freedesktop/systemd1/unit/dev_2dttyS0_2edevice {
interface org.freedesktop.systemd1.Device {
properties:
readonly s SysFSPath = '...';
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Device"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Device"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Device"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="SysFSPath"/>
<!--End of Autogenerated section-->
interface (described here) in addition to the generic
<interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Mount">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/home_2emount
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/home_2emount" interface="org.freedesktop.systemd1.Mount">
node /org/freedesktop/systemd1/unit/home_2emount {
interface org.freedesktop.systemd1.Mount {
methods:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Mount"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Mount"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Mount"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
<interfacename>org.freedesktop.systemd1.Automount</interfacename> interface (described here) in addition
to the generic <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Automount">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount" interface="org.freedesktop.systemd1.Automount">
node /org/freedesktop/systemd1/unit/proc_2dsys_2dfs_2dbinfmt_5fmisc_2eautomount {
interface org.freedesktop.systemd1.Automount {
properties:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Automount"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Automount"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Automount"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Where"/>
<variablelist class="dbus-property" generated="True" extra-ref="DirectoryMode"/>
interface (described here) in addition to the generic
<interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Timer">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer" interface="org.freedesktop.systemd1.Timer">
node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
interface org.freedesktop.systemd1.Timer {
properties:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Timer"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Timer"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Timer"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Unit"/>
<variablelist class="dbus-property" generated="True" extra-ref="TimersMonotonic"/>
interface (described here) in addition to the generic
<interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Swap">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/dev_2dsda3_2eswap" interface="org.freedesktop.systemd1.Swap">
node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
interface org.freedesktop.systemd1.Swap {
methods:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Swap"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Swap"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Swap"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
<refsect1>
<title>Path Unit Objects</title>
- <programlisting interface="org.freedesktop.systemd1.Path">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/cups_2epath
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/cups_2epath" interface="org.freedesktop.systemd1.Path">
node /org/freedesktop/systemd1/unit/cups_2epath {
interface org.freedesktop.systemd1.Path {
properties:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Path"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Path"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Path"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="Unit"/>
<variablelist class="dbus-property" generated="True" extra-ref="Paths"/>
interface (described here) in addition to the generic
<interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Slice">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/system_2eslice
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/system_2eslice" interface="org.freedesktop.systemd1.Slice">
node /org/freedesktop/systemd1/unit/system_2eslice {
interface org.freedesktop.systemd1.Slice {
methods:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Slice"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Slice"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Slice"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
<variablelist class="dbus-method" generated="True" extra-ref="AttachProcesses()"/>
interface (described here) in addition to the generic
<interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
- <programlisting interface="org.freedesktop.systemd1.Scope">
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/unit/session_2d1_2escope
-
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/unit/session_2d1_2escope" interface="org.freedesktop.systemd1.Scope">
node /org/freedesktop/systemd1/unit/session_2d1_2escope {
interface org.freedesktop.systemd1.Scope {
methods:
<!--Autogenerated cross-references for systemd.directives, do not edit-->
- <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Scope"/>
-
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Scope"/>
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
+ <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Scope"/>
+
<variablelist class="dbus-method" generated="True" extra-ref="Abandon()"/>
<variablelist class="dbus-method" generated="True" extra-ref="GetProcesses()"/>
<para>Job objects encapsulate scheduled or running jobs. Each unit can have none or one jobs in the
execution queue. Each job is attached to exactly one unit.</para>
- <programlisting>
-$ gdbus introspect --system --dest org.freedesktop.systemd1 \
- --object-path /org/freedesktop/systemd1/job/1292
-
-node /org/freedesktop/systemd1/job/1292 {
+ <programlisting executable="systemd" node="/org/freedesktop/systemd1/job/666" interface="org.freedesktop.systemd1.Job">
+node /org/freedesktop/systemd1/job/666 {
interface org.freedesktop.systemd1.Job {
methods:
Cancel();
</refsect2>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.systemd1.Manager</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.systemd1 \
+ --object-path /org/freedesktop/systemd1
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect a unit on the bus</title>
+
+ <programlisting>
+$ busctl introspect org.freedesktop.systemd1 \
+ $(busctl call org.freedesktop.systemd1 \
+ /org/freedesktop/systemd1 \
+ org.freedesktop.systemd1.Manager \
+ GetUnit s systemd-resolved.service | cut -d'"' -f2)
+ </programlisting>
+ </example>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.systemd1.Job</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system --dest org.freedesktop.systemd1 \
+ --object-path /org/freedesktop/systemd1/job/1292
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<para>The service exposes the following interfaces on the bus:</para>
- <programlisting>
-$ gdbus introspect --system \
- --dest org.freedesktop.timedate1 \
- --object-path /org/freedesktop/timedate1
-
+ <programlisting executable="systemd-timedated" node="/org/freedesktop/timedate1" interface="org.freedesktop.timedate1">
node /org/freedesktop/timedate1 {
interface org.freedesktop.timedate1 {
methods:
};
</programlisting>
- <!--method ListTimezones is not documented!-->
-
- <!--property Timezone is not documented!-->
-
- <!--property LocalRTC is not documented!-->
-
- <!--property CanNTP is not documented!-->
-
- <!--property NTP is not documented!-->
-
- <!--property NTPSynchronized is not documented!-->
-
- <!--property TimeUSec is not documented!-->
-
- <!--property RTCTimeUSec is not documented!-->
-
<!--Autogenerated cross-references for systemd.directives, do not edit-->
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.timedate1"/>
network using <filename>systemd-timesyncd</filename>. This will enable and start or disable and stop
the chosen time synchronization service.</para>
- <para>Whenever the timezone and local_rtc settings are changed via the daemon,
- <function>PropertyChanged</function> signals are sent out to which clients can subscribe. Changing the
- time settings using this interface is authenticated via PolicyKit.</para>
+ <para><function>ListTimezones()</function> returns a list of time zones known on the local system as an
+ array of names (<literal>["Africa/Abidjan", "Africa/Accra", ..., "UTC"]</literal>).</para>
+ </refsect2>
+
+ <refsect2>
+ <title>Properties</title>
+
+ <para><varname>Timezone</varname> shows the currently configured time zone.
+ <varname>LocalRTC</varname> shows whether the RTC is configured to use UTC (false), or the local time
+ zone (true). <varname>CanNTP</varname> shows whether a service to perform time synchronization over the
+ network is available, and <varname>NTP</varname> shows whether such a service is enabled.</para>
+
+ <para><varname>NTPSynchronized</varname> shows whether the kernel reports the time as synchronized
+ (c.f.
+ <citerefentry project="man-pages"><refentrytitle>adjtimex</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+ <varname>TimeUSec</varname> and <varname>RTCTimeUSec</varname> show the current time on the system and
+ in the RTC. The purpose of those three properties is to allow remote clients to access this information
+ over D-Bus. Local clients can access the information directly.</para>
+
+ <para>Whenever the <varname>Timezone</varname> and <varname>LocalRTC</varname> settings are changed via
+ the daemon, <function>PropertyChanged</function> signals are sent out to which clients can subscribe.
+ </para>
<para>Note that this service will not inform you about system time changes. Use
<citerefentry project="man-pages"><refentrytitle>timerfd</refentrytitle><manvolnum>3</manvolnum></citerefentry>
with <constant>CLOCK_REALTIME</constant> and <constant>TFD_TIMER_CANCEL_ON_SET</constant> for that.
</para>
+ </refsect2>
- <para>The <varname>user_interaction</varname> boolean parameters can be used to control whether
- PolicyKit should interactively ask the user for authentication credentials if required.</para>
+ <refsect2>
+ <title>Security</title>
+
+ <para>The <varname>interactive</varname> boolean parameters can be used to control whether
+ <ulink url="https://www.freedesktop.org/software/polkit/docs/latest/">polkit</ulink>
+ should interactively ask the user for authentication credentials if required.</para>
- <para>The PolicyKit action for <function>SetTimezone()</function> is
+ <para>The polkit action for <function>SetTimezone()</function> is
<interfacename>org.freedesktop.timedate1.set-timezone</interfacename>. For
<function>SetLocalRTC()</function> it is
<interfacename>org.freedesktop.timedate1.set-local-rtc</interfacename>, for
<function>SetTime()</function> it is <interfacename>org.freedesktop.timedate1.set-time</interfacename>
and for <function>SetNTP()</function> it is
- <interfacename>org.freedesktop.timedate1.set-ntp</interfacename>.</para>
+ <interfacename>org.freedesktop.timedate1.set-ntp</interfacename>.
+ <function>ListTimezones()</function> does not require any privileges.
+ </para>
</refsect2>
</refsect1>
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Introspect <interfacename>org.freedesktop.timedate1</interfacename> on the bus</title>
+
+ <programlisting>
+$ gdbus introspect --system \
+ --dest org.freedesktop.timedate1 \
+ --object-path /org/freedesktop/timedate1
+ </programlisting>
+ </example>
+ </refsect1>
+
<refsect1>
<title>Versioning</title>
<variablelist class='pam-directives'>
<varlistentry>
- <term><varname>systemd.memory_max</varname></term>
+ <term><varname>systemd.memory_max=</varname></term>
<listitem><para>Sets unit <varname>MemoryMax=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>systemd.tasks_max</varname></term>
+ <term><varname>systemd.tasks_max=</varname></term>
<listitem><para>Sets unit <varname>TasksMax=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>systemd.cpu_weight</varname></term>
+ <term><varname>systemd.cpu_weight=</varname></term>
<listitem><para>Sets unit <varname>CPUWeight=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>systemd.io_weight</varname></term>
+ <term><varname>systemd.io_weight=</varname></term>
<listitem><para>Sets unit <varname>IOWeight=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>systemd.runtime_max_sec</varname></term>
+ <term><varname>systemd.runtime_max_sec=</varname></term>
<listitem><para>Sets unit <varname>RuntimeMaxSec=</varname>.</para></listitem>
</varlistentry>
<filename>systemd-logind.service</filename>:</para>
<programlisting>#%PAM-1.0
-auth sufficient pam_unix.so
-auth required pam_deny.so
-
-account required pam_nologin.so
-account sufficient pam_unix.so
-account required pam_permit.so
-
-password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
-password required pam_deny.so
-
--session optional pam_loginuid.so
--session optional pam_systemd.so
-session required pam_unix.so</programlisting>
+auth sufficient pam_unix.so
+-auth sufficient pam_systemd_home.so
+auth required pam_deny.so
+
+account required pam_nologin.so
+-account sufficient pam_systemd_home.so
+account sufficient pam_unix.so
+account required pam_permit.so
+
+-password sufficient pam_systemd_home.so
+password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
+password required pam_deny.so
+
+-session optional pam_keyinit.so revoke
+-session optional pam_loginuid.so
+-session optional pam_systemd_home.so
+<command>-session optional pam_systemd.so</command>
+session required pam_unix.so</programlisting>
</refsect1>
<refsect1>
the re-authentication must take place from a component running outside of the user's context, so that
it does not require access to the user's home directory for operation. Traditionally, most desktop
environments do not implement screen locking this way, and need to be updated
- accordingly.</para></listitem>
+ accordingly.</para>
+
+ <para>This setting may also be controlled via the <varname>$SYSTEMD_HOME_SUSPEND</varname>
+ environment variable (see below), which <command>pam_systemd_home</command> reads during initialization and sets
+ for sessions. If both the environment variable is set and the module parameter specified the latter
+ takes precedence.</para></listitem>
</varlistentry>
<varlistentry>
<listitem><para>Indicates that the user's home directory is managed by <filename>systemd-homed.service</filename>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>$SYSTEMD_HOME_SUSPEND=</varname></term>
+
+ <listitem><para>Indicates whether the session has been registered with the suspend mechanism enabled
+ or disabled (see above). The variable's value is either <literal>0</literal> or
+ <literal>1</literal>. Note that the module both reads the variable when initializing, and sets it for
+ sessions.</para></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
<programlisting>#%PAM-1.0
auth sufficient pam_unix.so
--auth sufficient pam_systemd_home.so
+<command>-auth sufficient pam_systemd_home.so</command>
auth required pam_deny.so
account required pam_nologin.so
--account sufficient pam_systemd_home.so
+<command>-account sufficient pam_systemd_home.so</command>
account sufficient pam_unix.so
account required pam_permit.so
--password sufficient pam_systemd_home.so
+<command>-password sufficient pam_systemd_home.so</command>
password sufficient pam_unix.so sha512 shadow try_first_pass try_authtok
password required pam_deny.so
-session optional pam_keyinit.so revoke
-session optional pam_loginuid.so
--session optional pam_systemd_home.so
+<command>-session optional pam_systemd_home.so</command>
-session optional pam_systemd.so
session required pam_unix.so</programlisting>
</refsect1>
interface the data was discovered. It also contains information on whether the information could be
authenticated. All data for which local DNSSEC validation succeeds is considered authenticated. Moreover all data
originating from local, trusted sources is also reported authenticated, including resolution of the local host
- name, the <literal>localhost</literal> host name or all data from <filename>/etc/hosts</filename>.</para>
+ name, the <literal>localhost</literal> hostname or all data from <filename>/etc/hosts</filename>.</para>
</refsect1>
<refsect1>
<varlistentry>
<term><varname>Domains=</varname></term>
<listitem><para>A space-separated list of domains. These domains are used as search suffixes when resolving
- single-label host names (domain names which contain no dot), in order to qualify them into fully-qualified
+ single-label hostnames (domain names which contain no dot), in order to qualify them into fully-qualified
domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name
with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search
domains listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any domains
-# Do not edit. Generated by make-man-rules.py.
+# Do not edit. Generated by update-man-rules.py.
# Update with:
# ninja -C build man/update-man-rules
manpages = [
['file-hierarchy', '7', [], ''],
['halt', '8', ['poweroff', 'reboot'], ''],
['homectl', '1', [], 'ENABLE_HOMED'],
+ ['homed.conf', '5', ['homed.conf.d'], 'ENABLE_RESOLVE'],
['hostname', '5', [], ''],
['hostnamectl', '1', [], 'ENABLE_HOSTNAMED'],
['hwdb', '7', [], 'ENABLE_HWDB'],
['nss-mymachines', '8', ['libnss_mymachines.so.2'], 'ENABLE_NSS_MYMACHINES'],
['nss-resolve', '8', ['libnss_resolve.so.2'], 'ENABLE_NSS_RESOLVE'],
['nss-systemd', '8', ['libnss_systemd.so.2'], 'ENABLE_NSS_SYSTEMD'],
+ ['org.freedesktop.LogControl1', '5', [], ''],
+ ['org.freedesktop.home1', '5', [], 'ENABLE_HOMED'],
['org.freedesktop.hostname1', '5', [], 'ENABLE_HOSTNAMED'],
['org.freedesktop.import1', '5', [], 'ENABLE_IMPORTD'],
['org.freedesktop.locale1', '5', [], 'ENABLE_LOCALED'],
['sd_bus_get_events', 'sd_bus_get_timeout', 'sd_bus_set_fd'],
''],
['sd_bus_get_n_queued_read', '3', ['sd_bus_get_n_queued_write'], ''],
+ ['sd_bus_get_name_creds', '3', ['sd_bus_get_owner_creds'], ''],
+ ['sd_bus_get_name_machine_id', '3', [], ''],
['sd_bus_is_open', '3', ['sd_bus_is_ready'], ''],
['sd_bus_list_names', '3', [], ''],
['sd_bus_message_append', '3', ['sd_bus_message_appendv'], ''],
''],
['sd_bus_message_get_type',
'3',
- ['sd_bus_message_get_errno',
+ ['sd_bus_message_get_creds',
+ 'sd_bus_message_get_errno',
'sd_bus_message_get_error',
'sd_bus_message_is_method_call',
'sd_bus_message_is_method_error',
'sd_bus_message_new_method_errorf'],
''],
['sd_bus_message_new_signal', '3', [], ''],
- ['sd_bus_message_read', '3', ['sd_bus_message_readv'], ''],
+ ['sd_bus_message_open_container',
+ '3',
+ ['sd_bus_message_close_container',
+ 'sd_bus_message_enter_container',
+ 'sd_bus_message_exit_container'],
+ ''],
+ ['sd_bus_message_read',
+ '3',
+ ['sd_bus_message_peek_type', 'sd_bus_message_readv'],
+ ''],
['sd_bus_message_read_array', '3', [], ''],
['sd_bus_message_read_basic', '3', [], ''],
['sd_bus_message_read_strv', '3', [], ''],
['sd_bus_message_verify_type', '3', [], ''],
['sd_bus_negotiate_fds',
'3',
- ['sd_bus_negotiate_creds', 'sd_bus_negotiate_timestamp'],
+ ['sd_bus_get_creds_mask',
+ 'sd_bus_negotiate_creds',
+ 'sd_bus_negotiate_timestamp'],
''],
['sd_bus_new',
'3',
['sd_bus_path_decode', 'sd_bus_path_decode_many', 'sd_bus_path_encode_many'],
''],
['sd_bus_process', '3', [], ''],
+ ['sd_bus_query_sender_creds', '3', ['sd_bus_query_sender_privilege'], ''],
['sd_bus_reply_method_error',
'3',
['sd_bus_reply_method_errno',
'sd_bus_release_name_async',
'sd_bus_request_name_async'],
''],
- ['sd_bus_send', '3', [], ''],
+ ['sd_bus_send', '3', ['sd_bus_send_to'], ''],
['sd_bus_set_address', '3', ['sd_bus_get_address', 'sd_bus_set_exec'], ''],
['sd_bus_set_close_on_exit', '3', ['sd_bus_get_close_on_exit'], ''],
['sd_bus_set_connected_signal', '3', ['sd_bus_get_connected_signal'], ''],
['sd_machine_get_class', '3', ['sd_machine_get_ifindices'], ''],
['sd_notify',
'3',
- ['sd_notifyf', 'sd_pid_notify', 'sd_pid_notify_with_fds', 'sd_pid_notifyf'],
+ ['sd_notify_barrier',
+ 'sd_notifyf',
+ 'sd_pid_notify',
+ 'sd_pid_notify_with_fds',
+ 'sd_pid_notifyf'],
''],
['sd_path_lookup', '3', ['sd_path_lookup_strv'], ''],
['sd_pid_get_owner_uid',
--- /dev/null
+#include <systemd/sd-bus.h>
+
+int append_strings_to_message(sd_bus_message *m, const char *const *arr) {
+ int r;
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return r;
+
+ for (const char *s = *arr; *s; s++) {
+ r = sd_bus_message_append(m, "s", s);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(m);
+}
--- /dev/null
+#include <stdio.h>
+
+#include <systemd/sd-bus.h>
+
+int read_strings_from_message(sd_bus_message *m) {
+ int r;
+
+ r = sd_bus_message_enter_container(m, 'a', "s");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ const char *s;
+
+ r = sd_bus_message_read(m, "s", &s);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ printf("%s\n", s);
+ }
+
+ return sd_bus_message_exit_container(m);
+}
<citerefentry><refentrytitle>sd_bus_get_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_bus_id</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_creds_mask</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_current_handler</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_current_message</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_current_slot</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_n_queued_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_name_machine_id</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_scope</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_tid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_get_unique_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_append_string_memfd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_append_strv</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_at_end</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_close_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_copy</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_dump</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_enter_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_exit_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_cookie</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_get_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_new_method_call</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_new_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_new_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_open_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_message_peek_type</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_read_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_read_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_path_encode</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_process</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_query_sender_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_query_sender_privilege</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_reply_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_request_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_send_to</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_allow_interactive_authorization</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_set_bus_client</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<para>These prefixes are intended to be used in conjunction with stderr-based logging (or stdout-based
logging) as implemented by systemd. If a systemd service definition file is configured with
- <varname>StandardError=journal</varname>, <varname>StandardError=syslog</varname> or
- <varname>StandardError=kmsg</varname> (and similar with <varname>StandardOutput=</varname>), these
- prefixes can be used to encode a log level in lines printed. This is similar to the kernel
- <function>printk()</function>-style logging. See
+ <varname>StandardError=journal</varname> or <varname>StandardError=kmsg</varname> (and similar with
+ <varname>StandardOutput=</varname>), these prefixes can be used to encode a log level in lines
+ printed. This is similar to the kernel <function>printk()</function>-style logging. See
<citerefentry><refentrytitle>klogctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> for more
information.</para>
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
- <funcprototype>
+ <funcprototype id="sd_bus_message_handler_t">
<funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus-vtable.h></funcsynopsisinfo>
- <funcprototype>
- <funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
- <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
- <paramdef>void *<parameter>userdata</parameter></paramdef>
- <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
- </funcprototype>
+ <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>typedef int (*<function>sd_bus_property_get_t</function>)</funcdef>
<para>
<constant>SD_BUS_VTABLE_END</constant>
</para>
+ <para>
+ <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET(
+ <replaceable>member</replaceable>,
+ <replaceable>args</replaceable>,
+ <replaceable>result</replaceable>,
+ <replaceable>handler</replaceable>,
+ <replaceable>offset</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_METHOD_WITH_ARGS(
+ <replaceable>member</replaceable>,
+ <replaceable>args</replaceable>,
+ <replaceable>result</replaceable>,
+ <replaceable>handler</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
<para>
<constant>SD_BUS_METHOD_WITH_NAMES_OFFSET(
<replaceable>member</replaceable>,
<replaceable>flags</replaceable>)
</constant>
</para>
+ <para>
+ <constant>SD_BUS_SIGNAL_WITH_ARGS(
+ <replaceable>member</replaceable>,
+ <replaceable>args</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
<para>
<constant>SD_BUS_SIGNAL_WITH_NAMES(
<replaceable>member</replaceable>,
</para>
<para>
<constant>SD_BUS_PARAM(<replaceable>name</replaceable>)</constant>
+ <constant>SD_BUS_ARGS(<replaceable>...</replaceable>)</constant>
+ <constant>SD_BUS_RESULT(<replaceable>...</replaceable>)</constant>
+ <constant>SD_BUS_NO_ARGS</constant>
+ <constant>SD_BUS_NO_RESULT</constant>
</para>
</funcsynopsis>
</refsynopsisdiv>
<listitem><para>Those must always be the first and last element.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant></term>
+ <term><constant>SD_BUS_METHOD_WITH_ARGS()</constant></term>
+
+ <listitem><para>Declare a D-Bus method with the name <replaceable>member</replaceable>,
+ arguments <replaceable>args</replaceable> and result <replaceable>result</replaceable>.
+ <replaceable>args</replaceable> expects a sequence of argument type/name pairs wrapped in the
+ <constant>SD_BUS_ARGS()</constant> macro. The elements at even indices in this list describe the
+ types of the method's arguments. The method's parameter signature is the concatenation of all the
+ string literals at even indices in <replaceable>args</replaceable>. If a method has no parameters,
+ pass <constant>SD_BUS_NO_ARGS</constant> to <replaceable>args</replaceable>. The elements at uneven
+ indices describe the names of the method's arguments. <replaceable>result</replaceable> expects a
+ sequence of type/name pairs wrapped in the <constant>SD_BUS_RESULT()</constant> macro in the same
+ format as <constant>SD_BUS_ARGS()</constant>. The method's result signature is the concatenation of
+ all the string literals at even indices in <replaceable>result</replaceable>. If a method has no
+ result, pass <constant>SD_BUS_NO_RESULT</constant> to <replaceable>result</replaceable>. Note that
+ argument types are expected to be quoted string literals and argument names are expected to be
+ unquoted string literals. See below for a complete example.</para>
+
+ <para>The handler function <replaceable>handler</replaceable> must be of type
+ <function>sd_bus_message_handler_t</function>. It will be called to handle the incoming messages
+ that call this method. It receives a pointer that is the <replaceable>userdata</replaceable>
+ parameter passed to the registration function offset by <replaceable>offset</replaceable> bytes.
+ This may be used to pass pointers to different fields in the same data structure to different
+ methods in the same vtable. To send a reply from <parameter>handler</parameter>, call
+ <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ with the message the callback was invoked with. Parameter <replaceable>flags</replaceable> is a
+ combination of flags, see below.</para>
+
+ <constant>SD_BUS_METHOD_WITH_ARGS()</constant> is a shorthand for calling
+ <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant> with an offset of zero.
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><constant>SD_BUS_METHOD_WITH_NAMES_OFFSET()</constant></term>
<term><constant>SD_BUS_METHOD_WITH_NAMES()</constant></term>
parameter signature <replaceable>signature</replaceable>, result signature
<replaceable>result</replaceable>. Parameters <replaceable>in_names</replaceable> and
<replaceable>out_names</replaceable> specify the argument names of the input and output
- arguments in the function signature. The handler function
- <replaceable>handler</replaceable> must be of type
- <function>sd_bus_message_handler_t</function>. It will be called to handle the incoming
- messages that call this method. It receives a pointer that is the
- <replaceable>userdata</replaceable> parameter passed to the registration function offset
- by <replaceable>offset</replaceable> bytes. This may be used to pass pointers to different
- fields in the same data structure to different methods in the same vtable. To send a reply
- from <parameter>handler</parameter>, call
- <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- with the message the callback was invoked with. <replaceable>in_names</replaceable> and
+ arguments in the function signature. <replaceable>in_names</replaceable> and
<replaceable>out_names</replaceable> should be created using the
- <constant>SD_BUS_PARAM()</constant> macro, see below. Parameter
- <replaceable>flags</replaceable> is a combination of flags, see below.</para>
+ <constant>SD_BUS_PARAM()</constant> macro, see below. In all other regards, this macro behaves
+ exactly the same as <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant>.</para>
<para><constant>SD_BUS_METHOD_WITH_NAMES()</constant>,
<constant>SD_BUS_METHOD_WITH_OFFSET()</constant>, and <constant>SD_BUS_METHOD()</constant>
are variants which specify zero offset (<replaceable>userdata</replaceable> parameter is
passed with no change), leave the names unset (i.e. no parameter names), or both.</para>
+
+ <para>Prefer using <constant>SD_BUS_METHOD_WITH_ARGS_OFFSET()</constant> and
+ <constant>SD_BUS_METHOD_WITH_ARGS()</constant> over these macros as they allow specifying argument
+ types and names next to each other which is less error-prone than first specifying all argument
+ types followed by specifying all argument names.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>SD_BUS_SIGNAL_WITH_ARGS()</constant></term>
+
+ <listitem><para>>Declare a D-Bus signal with the name <replaceable>member</replaceable> and
+ arguments <replaceable>args</replaceable>. <replaceable>args</replaceable> expects a sequence of
+ argument type/name pairs wrapped in the <constant>SD_BUS_ARGS()</constant> macro. The elements at
+ even indices in this list describe the types of the signal's arguments. The signal's parameter
+ signature is the concatenation of all the string literals at even indices in
+ <replaceable>args</replaceable>. If a signal has no parameters, pass
+ <constant>SD_BUS_NO_ARGS</constant> to <replaceable>args</replaceable>. The elements at uneven
+ indices describe the names of the signal's arguments. Parameter <replaceable>flags</replaceable> is
+ a combination of flags. See below for a complete example.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><constant>SD_BUS_SIGNAL_WITH_NAMES()</constant></term>
<term><constant>SD_BUS_SIGNAL()</constant></term>
Parameter <replaceable>flags</replaceable> is a combination of flags, see below.
</para>
- <para>Equivalent to <constant>SD_BUS_SIGNAL_WITH_NAMES()</constant> with the
- <replaceable>names</replaceable> parameter unset (i.e. no parameter names).</para>
+ <para><constant>SD_BUS_SIGNAL()</constant> is equivalent to
+ <constant>SD_BUS_SIGNAL_WITH_NAMES()</constant> with the <replaceable>names</replaceable> parameter
+ unset (i.e. no parameter names).</para>
+
+ <para>Prefer using <constant>SD_BUS_SIGNAL_WITH_ARGS()</constant> over these macros as it allows
+ specifying argument types and names next to each other which is less error-prone than first
+ specifying all argument types followed by specifying all argument names.</para>
</listitem>
</varlistentry>
This corresponds to the <constant>org.freedesktop.systemd1.Explicit</constant> annotation
in introspection data.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_SENSITIVE</constant></term>
+
+ <listitem><para>Mark this vtable method entry as processing sensitive data. When set,
+ incoming method call messages and their outgoing reply messages are marked as sensitive using
+ <citerefentry><refentrytitle>sd_bus_message_sensitive</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ so that they are erased from memory when freed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_ABSOLUTE_OFFSET</constant></term>
+
+ <listitem><para>Mark this vtable method or property entry so that the user data pointer passed to
+ its associated handler functions is determined slightly differently: instead of adding the offset
+ parameter of the entry to the user data pointer specified during vtable registration, the offset is
+ passed directly, converted to a pointer, without taking the user data pointer specified during
+ vtable registration into account.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect2>
</refsect1>
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+ <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
<funcprototype>
<funcdef>int <function>sd_bus_call</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
received a D-Bus error reply), <parameter>ret_error</parameter> is initialized to an instance of
<structname>sd_bus_error</structname> describing the error.</para>
- <para><function>sd_bus_call_async()</function> is like <function>sd_bus_call()</function> but
- works asynchronously. The <parameter>callback</parameter> indicates the function to call when
- the response arrives. The <parameter>userdata</parameter> pointer will be passed to the callback
- function, and may be chosen freely by the caller. If <parameter>slot</parameter> is not
- <constant>NULL</constant> and <function>sd_bus_call_async()</function> succeeds,
- <parameter>slot</parameter> is set to a slot object which can be used to cancel the method call
- at a later time using
+ <para><function>sd_bus_call_async()</function> is like <function>sd_bus_call()</function> but works
+ asynchronously. The <parameter>callback</parameter> indicates the function to call when the response
+ arrives. The <parameter>userdata</parameter> pointer will be passed to the callback function, and may be
+ chosen freely by the caller. If <parameter>slot</parameter> is not <constant>NULL</constant> and
+ <function>sd_bus_call_async()</function> succeeds, <parameter>slot</parameter> is set to a slot object
+ which can be used to cancel the method call at a later time using
<citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
- If <parameter>slot</parameter> is <constant>NULL</constant>, the lifetime of the method call is
- bound to the lifetime of the bus object itself, and it cannot be cancelled independently. See
+ If <parameter>slot</parameter> is <constant>NULL</constant>, the lifetime of the method call is bound to
+ the lifetime of the bus object itself, and it cannot be cancelled independently. See
<citerefentry><refentrytitle>sd_bus_slot_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details. <parameter>callback</parameter> is called when a reply arrives with the reply,
- <parameter>userdata</parameter> and an <structname>sd_bus_error</structname> output
- parameter as its arguments. Unlike <function>sd_bus_call()</function>, the
- <structname>sd_bus_error</structname> output parameter passed to the callback will be empty. To
- determine whether the method call succeeded, use
+ <parameter>userdata</parameter> and an <structname>sd_bus_error</structname> output parameter as its
+ arguments. Unlike <function>sd_bus_call()</function>, the <structname>sd_bus_error</structname> output
+ parameter passed to the callback will be empty. To determine whether the method call succeeded, use
<citerefentry><refentrytitle>sd_bus_message_is_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>
on the reply message passed to the callback instead. If the callback returns zero and the
- <structname>sd_bus_error</structname> output parameter is still empty when the callback
- inishes, other handlers registered with functions such as
+ <structname>sd_bus_error</structname> output parameter is still empty when the callback finishes, other
+ handlers registered with functions such as
<citerefentry><refentrytitle>sd_bus_add_filter</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
- <citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- are given a chance to process the message. If the callback returns a non-zero value or the
- <structname>sd_bus_error</structname> output parameter is not empty when the callback finishes,
- no further processing of the message is done. Generally, you want to return zero from the
- callback to give other registered handlers a chance to process the reply as well.</para>
+ <citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry> are
+ given a chance to process the message. If the callback returns a non-zero value or the
+ <structname>sd_bus_error</structname> output parameter is not empty when the callback finishes, no
+ further processing of the message is done. Generally, you want to return zero from the callback to give
+ other registered handlers a chance to process the reply as well. (Note that the
+ <structname>sd_bus_error</structname> parameter is an output parameter of the callback function, not an
+ input parameter; it can be used to propagate errors from the callback handler, it will not receive any
+ error that was received as method reply.)</para>
<para>If <parameter>usec</parameter> is zero, the default D-Bus method call timeout is used. See
<citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+ <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
<funcprototype>
<funcdef>int <function>sd_bus_call_method</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+ <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
<funcprototype>
<funcdef>sd_bus_message_handler_t <function>sd_bus_get_current_handler</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
--- /dev/null
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_get_name_creds" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>sd_bus_get_name_creds</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_get_name_creds</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_get_name_creds</refname>
+ <refname>sd_bus_get_owner_creds</refname>
+
+ <refpurpose>Query bus client credentials</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_name_creds</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>uint64_t <parameter>mask</parameter></paramdef>
+ <paramdef>sd_bus_creds **<parameter>creds</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_owner_creds</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>uint64_t <parameter>mask</parameter></paramdef>
+ <paramdef>sd_bus_creds **<parameter>creds</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_get_name_creds()</function> queries the credentials of the bus client
+ identified by <parameter>name</parameter>. The <parameter>mask</parameter> parameter is a combo of
+ <constant index='false'>SD_BUS_CREDS_*</constant> flags that indicate which credential info the caller is
+ interested in. See
+ <citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ for a list of possible flags. On success, <parameter>creds</parameter> contains a new
+ <structname>sd_bus_creds</structname> instance with the requested information. Ownership of this instance
+ belongs to the caller and it should be freed once no longer needed by calling
+ <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ </para>
+
+ <para><function>sd_bus_get_owner_creds()</function> queries the credentials of the creator of the given
+ bus. The <parameter>mask</parameter> and <parameter>creds</parameter> parameters behave the same as in
+ <function>sd_bus_get_name_creds()</function>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return a non-negative integer. On failure, they return a negative
+ errno-style error code.</para>
+
+ <refsect2>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>An argument is invalid.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOPKG</constant></term>
+
+ <listitem><para>The bus cannot be resolved.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EPERM</constant></term>
+
+ <listitem><para>The bus has already been started.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus was created in a different process.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOMEM</constant></term>
+
+ <listitem><para>Memory allocation failed.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <xi:include href="libsystemd-pkgconfig.xml" />
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+</refentry>
--- /dev/null
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_get_name_machine_id" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>sd_bus_get_name_machine_id</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_get_name_machine_id</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_get_name_machine_id</refname>
+
+ <refpurpose>Retrieve a bus client's machine identity</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_name_machine_id</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>name</parameter></paramdef>
+ <paramdef>sd_id128_t *<parameter>machine</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_get_name_machine_id()</function> retrieves the D-Bus machine identity of the
+ machine that the bus client identified by <parameter>name</parameter> is running on. Internally, it calls
+ the <function>GetMachineId</function> method of the <constant>org.freedesktop.DBus.Peer</constant>
+ interface. The D-Bus machine identity is a 128-bit UUID. On Linux systems running systemd, this
+ corresponds to the contents of <filename>/etc/machine-id</filename>. On success, the machine identity is
+ stored in <parameter>machine</parameter>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, this function returns a non-negative integer. On failure, it returns a negative
+ errno-style error code.</para>
+
+ <refsect2>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>An argument is invalid.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOPKG</constant></term>
+
+ <listitem><para>The bus cannot be resolved.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus was created in a different process.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOMEM</constant></term>
+
+ <listitem><para>Memory allocation failed.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <xi:include href="libsystemd-pkgconfig.xml" />
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_append_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_bus_message_append_array</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_message_open_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
<funcdef>int sd_bus_message_append_array</funcdef>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<paramdef>char <parameter>type</parameter></paramdef>
- <paramdef>char void *<parameter>ptr</parameter></paramdef>
+ <paramdef>void *<parameter>ptr</parameter></paramdef>
<paramdef>size_t <parameter>size</parameter></paramdef>
</funcprototype>
<refname>sd_bus_message_get_type</refname>
<refname>sd_bus_message_get_error</refname>
<refname>sd_bus_message_get_errno</refname>
+ <refname>sd_bus_message_get_creds</refname>
<refname>sd_bus_message_is_signal</refname>
<refname>sd_bus_message_is_method_call</refname>
<refname>sd_bus_message_is_method_error</refname>
- <refpurpose>Query bus message addressing metadata</refpurpose>
+ <refpurpose>Query bus message addressing/credentials metadata</refpurpose>
</refnamediv>
<refsynopsisdiv>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
</funcprototype>
+ <funcprototype>
+ <funcdef>sd_bus_creds* <function>sd_bus_message_get_creds</function></funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ </funcprototype>
+
<funcprototype>
<funcdef>int <function>sd_bus_message_is_signal</function></funcdef>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
+ <para><function>sd_bus_message_get_creds()</function> returns the message credentials attached to the
+ message <parameter>m</parameter>. If no credentials are attached to the message, it returns
+ <constant>NULL</constant>. Ownership of the credentials instance is not transferred to the caller and
+ hence should not be freed.</para>
+
<para><function>sd_bus_message_is_signal()</function> checks if message <parameter>m</parameter> is a
signal message. If <parameter>interface</parameter> is non-null, it also checks if the message has the
same interface set. If <parameter>member</parameter> is non-null, it also checks if the message has the
<refsect1>
<title>Return Value</title>
- <para>On success, these functions return a non-negative integer. On failure, they return a negative
- errno-style error code. <function>sd_bus_message_get_errno()</function> always returns a non-negative
- integer, even on failure.</para>
+ <para>On success, these functions (except <function>sd_bus_message_get_error()</function> and
+ <function>sd_bus_message_get_creds()</function>) return a non-negative integer. On failure, they return a
+ negative errno-style error code. <function>sd_bus_message_get_errno()</function> always returns a
+ non-negative integer, even on failure.</para>
<refsect2>
<title>Errors</title>
--- /dev/null
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_message_open_container"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>sd_bus_message_open_container</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_message_open_container</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_message_open_container</refname>
+ <refname>sd_bus_message_close_container</refname>
+ <refname>sd_bus_message_enter_container</refname>
+ <refname>sd_bus_message_exit_container</refname>
+
+ <refpurpose>Create and move between containers in D-Bus messages</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int sd_bus_message_open_container</funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>char <parameter>type</parameter></paramdef>
+ <paramdef>const char *<parameter>contents</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int sd_bus_message_close_container</funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int sd_bus_message_enter_container</funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>char <parameter>type</parameter></paramdef>
+ <paramdef>const char *<parameter>contents</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int sd_bus_message_exit_container</funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_message_open_container()</function> appends a new container to the message
+ <parameter>m</parameter>. After opening a new container, it can be filled with content using
+ <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ and similar functions. Containers behave like a stack. To nest containers inside each other, call
+ <function>sd_bus_message_open_container()</function> multiple times without calling
+ <function>sd_bus_message_close_container()</function> in between. Each container will be nested inside the
+ previous container. <parameter>type</parameter> represents the container type and should be one of
+ <literal>r</literal>, <literal>a</literal>, <literal>v</literal> or <literal>e</literal> as described in
+ <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ Instead of literals, the corresponding constants <constant>SD_BUS_TYPE_STRUCT</constant>,
+ <constant>SD_BUS_TYPE_ARRAY</constant>, <constant>SD_BUS_TYPE_VARIANT</constant> or
+ <constant>SD_BUS_TYPE_DICT_ENTRY</constant> can also be used. <parameter>contents</parameter> describes
+ the type of the container's elements and should be a D-Bus type string following the rules described in
+ <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ </para>
+
+ <para><function>sd_bus_message_close_container()</function> closes the last container opened with
+ <function>sd_bus_message_open_container()</function>. On success, the write pointer of the message
+ <parameter>m</parameter> is positioned after the closed container in its parent container or in
+ <parameter>m</parameter> itself if there is no parent container.</para>
+
+ <para><function>sd_bus_message_enter_container()</function> enters the next container of the message
+ <parameter>m</parameter>. It behaves mostly the same as
+ <function>sd_bus_message_open_container()</function>. Entering a container allows reading its contents
+ with
+ <citerefentry><refentrytitle>sd_bus_message_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ and similar functions. <parameter>type</parameter> and <parameter>contents</parameter> are the same as in
+ <function>sd_bus_message_open_container()</function>.</para>
+
+ <para><function>sd_bus_message_exit_container()</function> exits the scope of the last container entered
+ with <function>sd_bus_message_enter_container()</function>. It behaves mostly the same as
+ <function>sd_bus_message_close_container()</function>.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return a non-negative integer. On failure, they return a negative
+ errno-style error code.</para>
+
+ <refsect2>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para><parameter>m</parameter> or <parameter>contents</parameter> are
+ <constant>NULL</constant> or <parameter>type</parameter> is invalid.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EPERM</constant></term>
+
+ <listitem><para>The message <parameter>m</parameter> is already sealed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ESTALE</constant></term>
+
+ <listitem><para>The message <parameter>m</parameter> is in an invalid state.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOMEM</constant></term>
+
+ <listitem><para>Memory allocation failed.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <xi:include href="libsystemd-pkgconfig.xml" />
+
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Append an array of strings to a message</title>
+
+ <programlisting><xi:include href="sd-bus-container-append.c" parse="text" /></programlisting>
+ </example>
+
+ <example>
+ <title>Read an array of strings from a message</title>
+
+ <programlisting><xi:include href="sd-bus-container-read.c" parse="text" /></programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_message_read</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <ulink url="https://dbus.freedesktop.org/doc/dbus-specification.html">The D-Bus specification</ulink>
+ </para>
+ </refsect1>
+
+</refentry>
<refnamediv>
<refname>sd_bus_message_read</refname>
<refname>sd_bus_message_readv</refname>
+ <refname>sd_bus_message_peek_type</refname>
<refpurpose>Read a sequence of values from a message</refpurpose>
</refnamediv>
<paramdef>const char *<parameter>types</parameter></paramdef>
<paramdef>va_list <parameter>ap</parameter></paramdef>
</funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_message_peek_type</function></funcdef>
+ <paramdef>char *<parameter>type</parameter></paramdef>
+ <paramdef>const char **<parameter>contents</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_bus_message_read()</function> reads a sequence of fields from
- the D-Bus message object <parameter>m</parameter> and advances the read position
- in the message. The type string <parameter>types</parameter> describes the types
- of items expected in the message and the field arguments that follow. The type
- string may be <constant>NULL</constant> or empty, in which case nothing is
- read.</para>
+ <para><function>sd_bus_message_read()</function> reads a sequence of fields from the D-Bus message object
+ <parameter>m</parameter> and advances the read position in the message. The type string
+ <parameter>types</parameter> describes the types of items expected in the message and the field arguments
+ that follow. The type string may be <constant>NULL</constant> or empty, in which case nothing is read.
+ </para>
<para>The type string is composed of the elements described in
<citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- i.e. basic and container types. It must contain zero or more single "complete
- types". The type string is <constant>NUL</constant>-terminated.</para>
-
- <para>For each type specified in the type string, one or more arguments need to be specified
- after the <parameter>types</parameter> parameter, in the same order. The arguments must be
- pointers to appropriate types (a pointer to <type>int8_t</type> for a <literal>y</literal> in
- the type string, a pointer to <type>int32_t</type> for an <literal>i</literal>, a pointer to
- <type>const char*</type> for an <literal>s</literal>, ...) which are set based on the values in
- the message. As an exception, in case of array and variant types, the first argument is an
- "input" argument that further specifies how the message should be read. See the table below for
- a complete list of allowed arguments and their types. Note that, if the basic type is a pointer
- (e.g., <type>const char *</type> in the case of a string), the argument is a pointer to a
- pointer, and also the pointer value that is written is only borrowed and the contents must be
- copied if they are to be used after the end of the messages lifetime.</para>
-
- <para>Each argument may also be <constant>NULL</constant>, in which case the value is read and
- ignored.</para>
+ i.e. basic and container types. It must contain zero or more single "complete types". The type string is
+ <constant>NUL</constant>-terminated.</para>
+
+ <para>For each type specified in the type string, one or more arguments need to be specified after the
+ <parameter>types</parameter> parameter, in the same order. The arguments must be pointers to appropriate
+ types (a pointer to <type>int8_t</type> for a <literal>y</literal> in the type string, a pointer to
+ <type>int32_t</type> for an <literal>i</literal>, a pointer to <type>const char*</type> for an
+ <literal>s</literal>, ...) which are set based on the values in the message. As an exception, in case of
+ array and variant types, the first argument is an "input" argument that further specifies how the message
+ should be read. See the table below for a complete list of allowed arguments and their types. Note that,
+ if the basic type is a pointer (e.g., <type>const char *</type> in the case of a string), the argument is
+ a pointer to a pointer, and also the pointer value that is written is only borrowed and the contents must
+ be copied if they are to be used after the end of the messages lifetime.</para>
+
+ <para>Each argument may also be <constant>NULL</constant>, in which case the value is read and ignored.
+ </para>
<table>
<title>Item type specifiers</title>
</tgroup>
</table>
- <para>If objects of the specified types are not present at the current position
- in the message, an error is returned.
- </para>
+ <para>If objects of the specified types are not present at the current position in the message, an error
+ is returned.</para>
<para>The <function>sd_bus_message_readv()</function> is equivalent to the
- <function>sd_bus_message_read()</function>, except that it is called with a
- <literal>va_list</literal> instead of a variable number of arguments. This
- function does not call the <function>va_end()</function> macro. Because it
- invokes the <function>va_arg()</function> macro, the value of
- <parameter>ap</parameter> is undefined after the call.</para>
+ <function>sd_bus_message_read()</function>, except that it is called with a <literal>va_list</literal>
+ instead of a variable number of arguments. This function does not call the <function>va_end()</function>
+ macro. Because it invokes the <function>va_arg()</function> macro, the value of <parameter>ap</parameter>
+ is undefined after the call.</para>
+
+ <para><function>sd_bus_message_peek_type()</function> determines the type of the next element in
+ <parameter>m</parameter> to be read by <function>sd_bus_message_read()</function> or similar functions.
+ On success, the type is stored in <parameter>type</parameter>, if it is not <constant>NULL</constant>.
+ If the type is a container type, the type of its elements is stored in <parameter>contents</parameter>,
+ if it is not <constant>NULL</constant>. If this function successfully determines the type of the next
+ element in <parameter>m</parameter>, it returns a positive integer. If there are no more elements to be
+ read, it returns zero.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para>On success, <function>sd_bus_message_read()</function> and
- <function>sd_bus_message_readv()</function> return 0 or a positive integer. On failure, they return a
- negative errno-style error code.</para>
+ <para>On success, these functions return a non-negative integer. On failure, they return a negative
+ errno-style error code.</para>
<xi:include href="sd_bus_message_read_basic.xml" xpointer="errors" />
</refsect1>
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_read_basic</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_skip</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_bus_message_append</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_message_enter_container</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
<refname>sd_bus_negotiate_fds</refname>
<refname>sd_bus_negotiate_timestamp</refname>
<refname>sd_bus_negotiate_creds</refname>
+ <refname>sd_bus_get_creds_mask</refname>
<refpurpose>Control feature negotiation on bus connections</refpurpose>
</refnamediv>
<paramdef>int <parameter>b</parameter></paramdef>
<paramdef>uint64_t <parameter>mask</parameter></paramdef>
</funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_get_creds_mask</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>uint64_t *<parameter>mask</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_bus_negotiate_fds()</function> controls whether
- file descriptor passing shall be negotiated for the specified bus
- connection. It takes a bus object and a boolean, which, when true,
- enables file descriptor passing, and, when false, disables
- it. Note that not all transports and servers support file
- descriptor passing. In particular, networked transports generally
- do not support file descriptor passing. To find out whether file
- descriptor passing is available after negotiation, use
+ <para><function>sd_bus_negotiate_fds()</function> controls whether file descriptor passing shall be
+ negotiated for the specified bus connection. It takes a bus object and a boolean, which, when true,
+ enables file descriptor passing, and, when false, disables it. Note that not all transports and servers
+ support file descriptor passing. In particular, networked transports generally do not support file
+ descriptor passing. To find out whether file descriptor passing is available after negotiation, use
<citerefentry><refentrytitle>sd_bus_can_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- and pass <constant>SD_BUS_TYPE_UNIX_FD</constant>. Note that file
- descriptor passing is always enabled for both sending and
- receiving or for neither, but never only in one direction. By
- default, file descriptor passing is negotiated for all
- connections.</para>
-
- <para><function>sd_bus_negotiate_timestamp()</function> controls whether implicit sender
- timestamps shall be attached automatically to all incoming messages. Takes a bus object and a
- boolean, which, when true, enables timestamping, and, when false, disables it. Use
+ and pass <constant>SD_BUS_TYPE_UNIX_FD</constant>. Note that file descriptor passing is always enabled
+ for both sending and receiving or for neither, but never only in one direction. By default, file
+ descriptor passing is negotiated for all connections.</para>
+
+ <para><function>sd_bus_negotiate_timestamp()</function> controls whether implicit sender timestamps shall
+ be attached automatically to all incoming messages. Takes a bus object and a boolean, which, when true,
+ enables timestamping, and, when false, disables it. Use
<citerefentry><refentrytitle>sd_bus_message_get_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_seqnum</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- to query the timestamps of incoming messages. If negotiation is disabled or not supported, these
- calls will fail with <constant>-ENODATA</constant>. Note that currently no transports support
- timestamping of messages. By default, message timestamping is not negotiated for
- connections.</para>
+ to query the timestamps of incoming messages. If negotiation is disabled or not supported, these calls
+ will fail with <constant>-ENODATA</constant>. Note that currently no transports support timestamping of
+ messages. By default, message timestamping is not negotiated for connections.</para>
<para><function>sd_bus_negotiate_creds()</function> controls whether and which implicit sender
- credentials shall be attached automatically to all incoming messages. Takes a bus object and a
- boolean indicating whether to enable or disable the credential parts encoded in the bit mask
- value argument. Note that not all transports support attaching sender credentials to messages,
- or do not support all types of sender credential parameters, or might suppress them under
- certain circumstances for individual messages. Specifically, dbus1 only supports
- <constant>SD_BUS_CREDS_UNIQUE_NAME</constant>. The sender credentials are suitable for
- authorization decisions. By default, only <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant> and
- <constant>SD_BUS_CREDS_UNIQUE_NAME</constant> are enabled. In fact, these two credential fields
- are always sent along and cannot be turned off.</para>
-
- <para>The <function>sd_bus_negotiate_fds()</function> function may
- be called only before the connection has been started with
+ credentials shall be attached automatically to all incoming messages. Takes a bus object and a boolean
+ indicating whether to enable or disable the credential parts encoded in the bit mask value argument. Note
+ that not all transports support attaching sender credentials to messages, or do not support all types of
+ sender credential parameters, or might suppress them under certain circumstances for individual messages.
+ Specifically, dbus1 only supports <constant>SD_BUS_CREDS_UNIQUE_NAME</constant>. The sender credentials
+ are suitable for authorization decisions. By default, only
+ <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant> and <constant>SD_BUS_CREDS_UNIQUE_NAME</constant> are
+ enabled. In fact, these two credential fields are always sent along and cannot be turned off.</para>
+
+ <para><function>sd_bus_get_creds_mask()</function> returns the set of sender credentials that was
+ negotiated to be attached to all incoming messages in <parameter>mask</parameter>. This value is an
+ upper boundary only. Hence, always make sure to explicitly check which credentials are attached to a
+ specific message before using it.</para>
+
+ <para>The <function>sd_bus_negotiate_fds()</function> function may be called only before the connection
+ has been started with
<citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Both
- <function>sd_bus_negotiate_timestamp()</function> and
- <function>sd_bus_negotiate_creds()</function> may also be called
- after a connection has been set up. Note that, when operating on a
- connection that is shared between multiple components of the same
- program (for example via
- <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>),
- it is highly recommended to only enable additional per message
- metadata fields, but never disable them again, in order not to
- disable functionality needed by other components.</para>
+ <function>sd_bus_negotiate_timestamp()</function> and <function>sd_bus_negotiate_creds()</function> may
+ also be called after a connection has been set up. Note that, when operating on a connection that is
+ shared between multiple components of the same program (for example via
+ <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>), it
+ is highly recommended to only enable additional per message metadata fields, but never disable them
+ again, in order not to disable functionality needed by other components.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para>On success, these functions return 0 or a
- positive integer. On failure, they return a negative errno-style
- error code.</para>
+ <para>On success, these functions return a non-negative integer. On failure, they return a negative
+ errno-style error code.</para>
<refsect2>
<title>Errors</title>
<listitem><para>The bus connection has already been started.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>An argument is invalid.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOPKG</constant></term>
+
+ <listitem><para>The bus cannot be resolved.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus was created in a different process.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect2>
</refsect1>
--- /dev/null
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_query_sender_creds" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>sd_bus_query_sender_creds</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_query_sender_creds</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_query_sender_creds</refname>
+ <refname>sd_bus_query_sender_privilege</refname>
+
+ <refpurpose>Query bus message sender credentials/privileges</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_query_sender_creds</function></funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>uint64_t <parameter>mask</parameter></paramdef>
+ <paramdef>sd_bus_creds **<parameter>creds</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>sd_bus_error* <function>sd_bus_query_sender_privilege</function></funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>int <parameter>capability</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_query_sender_creds()</function> returns the credentials of the message
+ <parameter>m</parameter>. The <parameter>mask</parameter> parameter is a combo of
+ <constant index='false'>SD_BUS_CREDS_*</constant> flags that indicate which credential info the caller is
+ interested in. See
+ <citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ for a list of possible flags. First, this message checks if the requested credentials are attached to the
+ message itself. If not but the message contains the pid of the sender, this function tries to figure out
+ the missing credentials via other means (starting from the pid). If the pid isn't available but the
+ message has a sender, this function calls
+ <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ to get the requested credentials. If the message has no sender (when a direct connection is used), this
+ function calls
+ <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ to get the requested credentials. On success, the requested credentials are stored in
+ <parameter>creds</parameter>. Ownership of the credentials object in <parameter>creds</parameter> is
+ transferred to the caller and should be freed by calling
+ <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ </para>
+
+ <para><function>sd_bus_query_sender_privilege()</function> checks if the message <parameter>m</parameter>
+ has the requested privileges. If <parameter>capability</parameter> is a non-negative integer, this
+ function checks if the message has the capability with the same value. See
+ <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ for a list of capabilities. If <parameter>capability</parameter> is a negative integer, this function
+ returns whether the sender of the message runs as the same user as the receiver of the message, or if the
+ sender of the message runs as root and the receiver of the message does not run as root. On success and
+ if the message has the requested privileges, this function returns a positive integer. If the message
+ does not have the requested privileges, this function returns zero.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return a non-negative integer. On failure, they return a negative
+ errno-style error code.</para>
+
+ <refsect2>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>The message <parameter>m</parameter> or an output parameter is
+ <constant>NULL</constant>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOTCONN</constant></term>
+
+ <listitem><para>The bus of <parameter>m</parameter> is not connected.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus of <parameter>m</parameter> was created in a different process.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EPERM</constant></term>
+
+ <listitem><para>The message <parameter>m</parameter> is not sealed.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <xi:include href="libsystemd-pkgconfig.xml" />
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+</refentry>
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+ <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
<funcprototype>
<funcdef>int <function>sd_bus_request_name</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
<refnamediv>
<refname>sd_bus_send</refname>
+ <refname>sd_bus_send_to</refname>
<refpurpose>Queue a D-Bus message for transfer</refpurpose>
</refnamediv>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<paramdef>uint64_t *<parameter>cookie</parameter></paramdef>
</funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_send_to</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>const char *<parameter>destination</parameter></paramdef>
+ <paramdef>uint64_t *<parameter>cookie</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_bus_send()</function> queues the bus message object <parameter>m</parameter>
- for transfer. If <parameter>bus</parameter> is <constant>NULL</constant>, the bus that
- <parameter>m</parameter> is attached to is used. <parameter>bus</parameter> only needs to be set
- when the message is sent to a different bus than the one it's attached to, for example when
- forwarding messages. If the output parameter <parameter>cookie</parameter> is not
- <constant>NULL</constant>, it is set to the message identifier. This value can later be used to
- match incoming replies to their corresponding messages. If <parameter>cookie</parameter> is set
- to <constant>NULL</constant> and the message is not sealed, <function>sd_bus_send()</function>
- assumes the message <parameter>m</parameter> doesn't expect a reply and adds the necessary
- headers to indicate this.</para>
+ <para><function>sd_bus_send()</function> queues the bus message object <parameter>m</parameter> for
+ transfer. If <parameter>bus</parameter> is <constant>NULL</constant>, the bus that
+ <parameter>m</parameter> is attached to is used. <parameter>bus</parameter> only needs to be set when the
+ message is sent to a different bus than the one it's attached to, for example when forwarding messages.
+ If the output parameter <parameter>cookie</parameter> is not <constant>NULL</constant>, it is set to the
+ message identifier. This value can later be used to match incoming replies to their corresponding
+ messages. If <parameter>cookie</parameter> is set to <constant>NULL</constant> and the message is not
+ sealed, <function>sd_bus_send()</function> assumes the message <parameter>m</parameter> doesn't expect a
+ reply and adds the necessary headers to indicate this.</para>
<para>Note that in most scenarios, <function>sd_bus_send()</function> should not be called
directly. Instead, use higher level functions such as
<citerefentry><refentrytitle>sd_bus_call_method</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
<citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
which call <function>sd_bus_send()</function> internally.</para>
+
+ <para><function>sd_bus_send_to()</function> is a shorthand for sending a message to a specific
+ destination. It's main use case is to simplify sending unicast signal messages (signals that only have a
+ single receiver). It's behavior is similar to calling
+ <citerefentry><refentrytitle>sd_bus_message_set_destination</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ followed by calling <function>sd_bus_send()</function>.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
- <para>On success, this function returns a non-negative integer. On failure, it returns a
- negative errno-style error code.</para>
+ <para>On success, these functions return a non-negative integer. On failure, they return a negative
+ errno-style error code.</para>
<refsect2 id='errors'>
<title>Errors</title>
<varlistentry>
<term><constant>-ECHILD</constant></term>
- <listitem><para>The bus connection was allocated in a parent process and is being reused
- in a child process after <function>fork()</function>.</para></listitem>
+ <listitem><para>The bus connection was allocated in a parent process and is being reused in a child
+ process after <function>fork()</function>.</para></listitem>
</varlistentry>
<varlistentry>
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_call_method</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_set_destination</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_bus_send_to</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_bus_reply_method_return</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
<funcsynopsis>
<funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo>
+ <xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
+
<funcprototype>
<funcdef>sd_bus *<function>sd_bus_slot_get_bus</function></funcdef>
<paramdef>sd_bus_slot *<parameter>slot</parameter></paramdef>
<refname>sd_pid_notify</refname>
<refname>sd_pid_notifyf</refname>
<refname>sd_pid_notify_with_fds</refname>
+ <refname>sd_notify_barrier</refname>
<refpurpose>Notify service manager about start-up completion and other service status changes</refpurpose>
</refnamediv>
<paramdef>const int *<parameter>fds</parameter></paramdef>
<paramdef>unsigned <parameter>n_fds</parameter></paramdef>
</funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_notify_barrier</function></funcdef>
+ <paramdef>int <parameter>unset_environment</parameter></paramdef>
+ <paramdef>uint64_t <parameter>timeout</parameter></paramdef>
+ </funcprototype>
</funcsynopsis>
</refsynopsisdiv>
in a <citerefentry><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> memory
file descriptor. Note that the service manager will accept messages for a service only if its
<varname>FileDescriptorStoreMax=</varname> setting is non-zero (defaults to zero, see
- <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If file
- descriptors sent are pollable (see
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>). If
+ <varname>FDPOLL=0</varname> is not set and the file descriptors sent are pollable (see
<citerefentry><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), then any
<constant>EPOLLHUP</constant> or <constant>EPOLLERR</constant> event seen on them will result in their
automatic removal from the store. Multiple arrays of file descriptors may be sent in separate messages, in
submitted name does not follow these restrictions, it is ignored.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term>FDPOLL=0</term>
+
+ <listitem><para>When used in combination with <varname>FDSTORE=1</varname>, disables polling of the stored
+ file descriptors regardless of whether or not they are pollable. As this option disables automatic cleanup
+ of the stored file descriptors on EPOLLERR and EPOLLHUP, care must be taken to ensure proper manual cleanup.
+ Use of this option is not generally recommended except for when automatic cleanup has unwanted behavior such
+ as prematurely discarding file descriptors from the store.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BARRIER=1</term>
+
+ <listitem><para>Tells the service manager that the client is explicitly requesting synchronization by means of
+ closing the file descriptor sent with this command. The service manager guarantees that the processing of a <varname>
+ BARRIER=1</varname> command will only happen after all previous notification messages sent before this command
+ have been processed. Hence, this command accompanied with a single file descriptor can be used to synchronize
+ against reception of all previous status messages. Note that this command cannot be mixed with other notifications,
+ and has to be sent in a separate message to the service manager, otherwise all assignments will be ignored. Note that
+ sending 0 or more than 1 file descriptor with this command is a violation of the protocol.</para></listitem>
+ </varlistentry>
</variablelist>
<para>It is recommended to prefix variable names that are not
attribute the message to the unit, and thus will ignore it, even if
<varname>NotifyAccess=</varname><option>all</option> is set for it.</para>
+ <para>Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of notifications
+ to units correctly, <function>sd_notify_barrier()</function> may be used. This call acts as a synchronization point
+ and ensures all notifications sent before this call have been picked up by the service manager when it returns
+ successfully. Use of <function>sd_notify_barrier()</function> is needed for clients which are not invoked by the
+ service manager, otherwise this synchronization mechanism is unnecessary for attribution of notifications to the
+ unit.</para>
+
<para><function>sd_notifyf()</function> is similar to
<function>sd_notify()</function> but takes a
<function>printf()</function>-like format string plus
to the service manager on messages that do not expect them (i.e.
without <literal>FDSTORE=1</literal>) they are immediately closed
on reception.</para>
+
+ <para><function>sd_notify_barrier()</function> allows the caller to
+ synchronize against reception of previously sent notification messages
+ and uses the <literal>BARRIER=1</literal> command. It takes a relative
+ <varname>timeout</varname> value in microseconds which is passed to
+ <citerefentry><refentrytitle>ppoll</refentrytitle><manvolnum>2</manvolnum>
+ </citerefentry>. A value of UINT64_MAX is interpreted as infinite timeout.
+ </para>
</refsect1>
<refsect1>
<programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &fd, 1);</programlisting>
</example>
+
+ <example>
+ <title>Eliminating race conditions</title>
+
+ <para>When the client sending the notifications is not spawned
+ by the service manager, it may exit too quickly and the service
+ manager may fail to attribute them correctly to the unit. To
+ prevent such races, use <function>sd_notify_barrier()</function>
+ to synchronize against reception of all notifications sent before
+ this call is made.</para>
+
+ <programlisting>sd_notify(0, "READY=1");
+ /* set timeout to 5 seconds */
+ sd_notify_barrier(0, 5 * 1000000);
+ </programlisting>
+ </example>
</refsect1>
<refsect1>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<tbody>
+ <row id='b'>
+ <entry><literal>%b</literal></entry>
+ <entry>Boot ID</entry>
+ <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
+ </row>
+ <row id='a'>
+ <entry><literal>%a</literal></entry>
+ <entry>Architecture</entry>
+ <entry>A short string identifying the architecture of the local system. A string such as <constant>x86</constant>, <constant>x86-64</constant> or <constant>arm64</constant>. See the architectures defined for <varname>ConditionArchitecture=</varname> in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for a full list.</entry>
+ </row>
+ <row id='B'>
+ <entry><literal>%B</literal></entry>
+ <entry>Operating system build ID</entry>
+ <entry>The operating system build identifier of the running system, as read from the <varname>BUILD_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+ </row>
+ <row id='H'>
+ <entry><literal>%H</literal></entry>
+ <entry>Host name</entry>
+ <entry>The hostname of the running system.</entry>
+ </row>
+ <row id='l'>
+ <entry><literal>%l</literal></entry>
+ <entry>Short host name</entry>
+ <entry>The hostname of the running system, truncated at the first dot to remove any domain component.</entry>
+ </row>
+ <row id='m'>
+ <entry><literal>%m</literal></entry>
+ <entry>Machine ID</entry>
+ <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+ </row>
+ <row id='o'>
+ <entry><literal>%o</literal></entry>
+ <entry>Operating system ID</entry>
+ <entry>The operating system identifier of the running system, as read from the <varname>ID=</varname> field of <filename>/etc/os-release</filename>. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+ </row>
+ <row id='v'>
+ <entry><literal>%v</literal></entry>
+ <entry>Kernel release</entry>
+ <entry>Identical to <command>uname -r</command> output.</entry>
+ </row>
+ <row id='w'>
+ <entry><literal>%w</literal></entry>
+ <entry>Operating system version ID</entry>
+ <entry>The operating system version identifier of the running system, as read from the <varname>VERSION_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+ </row>
+ <row id='W'>
+ <entry><literal>%W</literal></entry>
+ <entry>Operating system variant ID</entry>
+ <entry>The operating system variant identifier of the running system, as read from the <varname>VARIANT_ID=</varname> field of <filename>/etc/os-release</filename>. If not set, resolves to an empty string. See <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
+ </row>
+ <row id='percent'>
+ <entry><literal>%%</literal></entry>
+ <entry>Single percent sign</entry>
+ <entry>Use <literal>%%</literal> in place of <literal>%</literal> to specify a single percent sign.</entry>
+ </row>
+</tbody>
<example>
<title>Set network routing properties for all interfaces</title>
- <para><filename>/etc/systemd/20-rp_filter.conf</filename>:</para>
+ <para><filename>/etc/sysctl.d/20-rp_filter.conf</filename>:</para>
<programlisting>net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.*.rp_filter = 2
generally redundant and reproducible on the next invocation of the unit).</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>freeze <replaceable>PATTERN</replaceable>…</command></term>
+
+ <listitem>
+ <para>Freeze one or more units specified on the
+ command line using cgroup freezer</para>
+
+ <para>Freezing the unit will cause all processes contained within the cgroup corresponding to the unit
+ to be suspended. Being suspended means that unit's processes won't be scheduled to run on CPU until thawed.
+ Note that this command is supported only on systems that use unified cgroup hierarchy. Unit is automatically
+ thawed just before we execute a job against the unit, e.g. before the unit is stopped.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>thaw <replaceable>PATTERN</replaceable>…</command></term>
+
+ <listitem>
+ <para>Thaw (unfreeze) one or more units specified on the
+ command line.</para>
+
+ <para>This is the inverse operation to the <command>freeze</command> command and resumes the execution of
+ processes in the unit's cgroup.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><command>is-active <replaceable>PATTERN</replaceable>…</command></term>
<row>
<entry><literal>linked-runtime</literal></entry>
</row>
+ <row>
+ <entry><literal>alias</literal></entry>
+ <entry>The name is an alias (symlink to another unit file).</entry>
+ <entry>0</entry>
+ </row>
<row>
<entry><literal>masked</literal></entry>
<entry morerows='1'>Completely disabled, so that any start operation on it fails (permanently in <filename>/etc/systemd/system/</filename> or transiently in <filename>/run/systemd/systemd/</filename>).</entry>
<refsect1><title>Options</title>
<variablelist>
+
+ <varlistentry>
+ <term><option>--unregister</option></term>
+ <listitem><para>If passed, instead of registering configured binary formats in the kernel, the
+ reverse operation is executed: all currently registered binary formats are unregistered from the
+ kernel.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="cat-config" />
<xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="help" />
<para>At early boot and when the system manager configuration is reloaded, <filename>/etc/crypttab</filename> is
translated into <filename>systemd-cryptsetup@.service</filename> units by
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+
+ <para>In order to unlock a volume a password or binary key is
+ required. <filename>systemd-cryptsetup@.service</filename> tries to acquire a suitable password or binary
+ key via the following mechanisms, tried in order:</para>
+
+ <orderedlist>
+ <listitem><para>If a key file is explicitly configured (via the third column in
+ <filename>/etc/crypttab</filename>), a key read from it is used. If a PKCS#11 token is configured
+ (using the <varname>pkcs11-uri=</varname> option) the key is decrypted before use.</para></listitem>
+
+ <listitem><para>If no key file is configured explicitly this way, a key file is automatically loaded
+ from <filename>/etc/cryptsetup-keys.d/<replaceable>volume</replaceable>.key</filename> and
+ <filename>/run/cryptsetup-keys.d/<replaceable>volume</replaceable>.key</filename>, if present. Here
+ too, if a PKCS#11 token is configured, any key found this way is decrypted before
+ use.</para></listitem>
+
+ <listitem><para>If the <varname>try-empty-password</varname> option is specified it is then attempted
+ to unlock the volume with an empty password.</para></listitem>
+
+ <listitem><para>The kernel keyring is then checked for a suitable cached password from previous
+ attempts.</para></listitem>
+
+ <listitem><para>Finally, the user is queried for a password, possibly multiple times.</para></listitem>
+ </orderedlist>
+
+ <para>If no suitable key may be acquired via any of the mechanisms describes above, volume activation fails.</para>
</refsect1>
<refsect1>
<listitem><para>The system time zone</para></listitem>
- <listitem><para>The system host name</para></listitem>
+ <listitem><para>The system hostname</para></listitem>
<listitem><para>The machine ID of the system</para></listitem>
<term><option>--hostname=<replaceable>HOSTNAME</replaceable></option></term>
<listitem><para>Sets the system hostname. The argument should
- be a host name, compatible with DNS. This controls the
+ be a hostname, compatible with DNS. This controls the
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>
configuration file.</para></listitem>
</varlistentry>
<citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</refsect1>
+ <refsect1>
+ <title>Key Management</title>
+
+ <para>User records are cryptographically signed with a public/private key pair (the signature is part of
+ the JSON record itself). For a user to be permitted to log in locally the public key matching the
+ signature of their user record must be installed. For a user record to be modified locally the private
+ key matching the signature must be installed locally, too. The keys are stored in the
+ <filename>/var/lib/systemd/home/</filename> directory:</para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><filename>/var/lib/systemd/home/local.private</filename></term>
+
+ <listitem><para>The private key of the public/private key pair used for local records. Currently,
+ only a single such key may be installed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/var/lib/systemd/home/local.public</filename></term>
+
+ <listitem><para>The public key of the public/private key pair used for local records. Currently,
+ only a single such key may be installed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/var/lib/systemd/home/*.public</filename></term>
+
+ <listitem><para>Additional public keys. Any users whose user records are signed with any of these keys
+ are permitted to log in locally. An arbitrary number of keys may be installed this
+ way.</para></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>All key files listed above are in PEM format.</para>
+
+ <para>In order to migrate a home directory from a host <literal>foobar</literal> to another host
+ <literal>quux</literal> it is hence sufficient to copy
+ <filename>/var/lib/systemd/home/local.public</filename> from the host <literal>foobar</literal> to
+ <literal>quux</literal>, maybe calling the file on the destination
+ <filename>/var/lib/systemd/home/foobar.public</filename>, reflecting the origin of the key. If the user
+ record should be modifiable on <literal>quux</literal> the pair
+ <filename>/var/lib/systemd/home/local.public</filename> and
+ <filename>/var/lib/systemd/home/local.private</filename> need to be copied from <literal>foobar</literal>
+ to <literal>quux</literal>, and placed under the identical paths there, as currently only a single
+ private key is supported per host. Note of course that the latter means that user records
+ generated/signed before the key pair is copied in, lose their validity.</para>
+ </refsect1>
+
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>pam_systemd_home</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>userdbctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>org.freedesktop.home1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
is a command line client to this service.</para>
<para>See
- <citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of the D-Bus API.</para>
</refsect1>
<command>pull-raw</command>, <command>pull-tar</command>, <command>import-raw</command>,
<command>import-tar</command>, <command>export-raw</command>, and <command>export-tar</command> commands.</para>
- <para>See the
- <ulink url="https://www.freedesktop.org/wiki/Software/systemd/importd">
- importd D-Bus API Documentation</ulink> for information about the
- APIs <filename>systemd-importd</filename> provides.</para>
+ <para>See
+ <citerefentry><refentrytitle>org.freedesktop.import1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for a description of the D-Bus API.</para>
</refsect1>
<refsect1>
is a command line client to this service.</para>
<para>See
- <citerefentry><refentrytitle>org.freedesktop.locale1</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>org.freedesktop.locale1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of the D-Bus API.</para>
</refsect1>
such as users, sessions and seats.</para>
<para>See
- <citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for information about the D-Bus APIs <filename>systemd-logind</filename> provides.</para>
<para>For more information on the inhibition logic see the <ulink
For more information please consult
<citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>
and
- <citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
<para>A small companion daemon
off the process, i.e. on all processes that match <varname>NotifyAccess=</varname><option>main</option> or
<varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit sends an
<function>sd_notify()</function> message and immediately exits, the service manager might not be able to properly
- attribute the message to the unit, and thus will ignore it, even if
- <varname>NotifyAccess=</varname><option>all</option> is set for it.</para>
-
- <para><command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function> pretending to
- have the PID of the invoking process. This will only succeed when invoked with sufficient privileges. On failure,
- it will then fall back to invoking it under its own PID. This behaviour is useful in order that when the tool is
- invoked from a shell script the shell process — and not the <command>systemd-notify</command> process — appears as
- sender of the message, which in turn is helpful if the shell process is the main process of a service, due to the
- limitations of <varname>NotifyAccess=</varname><option>all</option> described above.</para>
+ attribute the message to the unit, and thus will ignore it, even if <varname>NotifyAccess=</varname><option>all
+ </option> is set for it. When <option>--no-block</option> is used, all synchronization for reception of notifications
+ is disabled, and hence the aforementioned race may occur if the invoking process is not the service manager or spawned
+ by the service manager.</para>
+
+ <para>Hence, <command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function>
+ pretending to have the PID of the invoking process. This will only succeed when invoked with sufficient privileges.
+ On failure, it will then fall back to invoking it under its own PID. This behaviour is useful in order that when
+ the tool is invoked from a shell script the shell process — and not the <command>systemd-notify</command> process
+ — appears as sender of the message, which in turn is helpful if the shell process is the main process of a service,
+ due to the limitations of <varname>NotifyAccess=</varname><option>all</option>. Use the <option>--pid=</option>
+ switch to tweak this behaviour.</para>
+
</refsect1>
<refsect1>
<varlistentry>
<term><option>--pid=</option></term>
- <listitem><para>Inform the init system about the main PID of
- the daemon. Takes a PID as argument. If the argument is
- omitted, the PID of the process that invoked
- <command>systemd-notify</command> is used. This is equivalent
- to <command>systemd-notify MAINPID=$PID</command>. For details
- about the semantics of this option see
+ <listitem><para>Inform the service manager about the main PID of the daemon. Takes a PID as
+ argument. If the argument is specified as <literal>auto</literal> or omitted, the PID of the process
+ that invoked <command>systemd-notify</command> is used, except if that's the service manager. If the
+ argument is specified as <literal>self</literal>, the PID of the <command>systemd-notify</command>
+ command itself is used, and if <literal>parent</literal> is specified the calling process' PID is
+ used — even if it is the service manager. This is equivalent to <command>systemd-notify
+ MAINPID=$PID</command>. For details about the semantics of this option see
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
with systemd. </para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-block</option></term>
+
+ <listitem><para>Do not synchronously wait for the requested operation to finish.
+ Use of this option is only recommended when <command>systemd-notify</command>
+ is spawned by the service manager, or when the invoking process is directly spawned
+ by the service manager and has enough privileges to allow <command>systemd-notify
+ </command> to send the notification on its behalf. Sending notifications with
+ this option set is prone to race conditions in all other cases.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
all subdirectories and subvolumes below it, but excluding any sub-mounts. May not be specified
together with <option>--image=</option> or <option>--ephemeral</option>.</para>
- <para>Note that this switch leaves host name, machine ID and
+ <para>Note that this switch leaves hostname, machine ID and
all other settings that could identify the instance
unmodified.</para></listitem>
</varlistentry>
<listitem><para>If specified, the container is run with a temporary snapshot of its file system that is removed
immediately when the container terminates. May not be specified together with
<option>--template=</option>.</para>
- <para>Note that this switch leaves host name, machine ID and all other settings that could identify
+ <para>Note that this switch leaves hostname, machine ID and all other settings that could identify
the instance unmodified. Please note that — as with <option>--template=</option> — taking the
temporary snapshot is more efficient on file systems that support subvolume snapshots or 'reflinks'
natively (<literal>btrfs</literal> or new <literal>xfs</literal>) than on more traditional file
<citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
</refsect2>
+
+ <refsect2>
+ <title>Controlling kernel parameters</title>
+
+ <para> The kernel has two parameters,
+ <filename>/sys/module/kernel/parameters/crash_kexec_post_notifiers</filename> and
+ <filename>/sys/module/printk/parameters/always_kmsg_dump</filename>,
+ that control writes into pstore.
+ The crash_kexec_post_notifiers parameter enables the kernel to write
+ dmesg (including stack trace) into pstore upon a panic or crash, and
+ printk.always_kmsg_dump parameter enables the kernel to write dmesg
+ upon a normal shutdown (shutdown, reboot, halt). These kernel
+ parameters are managed via the
+ <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ mechanism, specifically the file <filename>/usr/lib/tmpfiles/systemd-pstore.conf</filename>.
+ </para>
+ </refsect2>
+
</refsect1>
<refsect1>
<itemizedlist>
<listitem><para>The root partition may be grown to cover the whole available disk space</para></listitem>
- <listitem><para>A <filename>/home/</filename>, swap or <filename>/srv</filename> partition can be added in</para></listitem>
+ <listitem><para>A <filename>/home/</filename>, swap or <filename>/srv/</filename> partition can be added in</para></listitem>
<listitem><para>A second (or third, …) root partition may be added in, to cover A/B style setups
where a second version of the root file system is alternatingly used for implementing update
schemes. The deployed image would carry only a single partition ("A") but on first boot a second
also be set explicitly, formatted as UUID via the <option>--seed=</option> option. By hashing these UUIDs
from a common seed images prepared with this tool become reproducible and the result of the algorithm
above deterministic.</para>
+
+ <para>The positional argument should specify the block device to operate on. Instead of a block device
+ node path a regular file may be specified too, in which case the command operates on it like it would if
+ a loopback block device node was specified with the file attached. If <option>--empty=create</option> is
+ specified the specified path is created as regular file, which is useful for generating disk images from
+ scratch.</para>
</refsect1>
<refsect1>
<varlistentry>
<term><option>--empty=</option></term>
<listitem><para>Takes one of <literal>refuse</literal>, <literal>allow</literal>,
- <literal>require</literal> or <literal>force</literal>. Controls how to operate on block devices that
- are entirely empty, i.e. carry no partition table/disk label yet. If this switch is not specified the
- implied default is <literal>refuse</literal>.</para>
+ <literal>require</literal>, <literal>force</literal> or <literal>create</literal>. Controls how to
+ operate on block devices that are entirely empty, i.e. carry no partition table/disk label yet. If
+ this switch is not specified the implied default is <literal>refuse</literal>.</para>
<para>If <literal>refuse</literal> <command>systemd-repart</command> requires that the block device
it shall operate on already carries a partition table and refuses operation if none is found. If
exists so far, and refuse operation if one already exists. If <literal>force</literal> it will create
a fresh partition table unconditionally, erasing the disk fully in effect. If
<literal>force</literal> no existing partitions will be taken into account or survive the
- operation. Hence: use with care, this is a great way to lose all your data.</para></listitem>
+ operation. Hence: use with care, this is a great way to lose all your data. If
+ <literal>create</literal> a new loopback file is create under the path passed via the device node
+ parameter, of the size indicated with <option>--size=</option>, see below.</para></listitem>
</varlistentry>
<varlistentry>
the implied default. Controls whether to issue the <constant>BLKDISCARD</constant> I/O control
command on the space taken up by any added partitions or on the space in between them. Usually, it's
a good idea to issue this request since it tells the underlying hardware that the covered blocks
- shall be considered empty, improving performance.</para></listitem>
+ shall be considered empty, improving performance. If operating on a regular file instead of a block
+ device node, a sparse file is generated.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--size=</option></term>
+
+ <listitem><para>Takes a size in bytes, using the usual K, M, G, T suffixes. If used the specified
+ device node path must refer to a regular file, which is then grown to the specified size if smaller,
+ before any change is made to the partition table. This is not supported if the specified node is a
+ block device. This switch has no effect if the file is already as large as the specified size or
+ larger. The specified size is implicitly rounded up to multiples of 4096. When used with
+ <option>--empty=create</option> this specifies the initial size of the loopback file to
+ create.</para></listitem>
</varlistentry>
<varlistentry>
<listitem><para>The native, fully-featured API <command>systemd-resolved</command> exposes on the bus,
see
<citerefentry><refentrytitle>org.freedesktop.resolve1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details. Usage of this API is generally recommended to clients as it is asynchronous and fully
featured (for example, properly returns DNSSEC validation status and interface scope for addresses as
necessary for supporting link-local networking).</para></listitem>
(<citerefentry project='man-pages'><refentrytitle>nss</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
Usage of the glibc NSS module
<citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
- required in order to allow glibc's NSS resolver functions to resolve host names via
+ required in order to allow glibc's NSS resolver functions to resolve hostnames via
<command>systemd-resolved</command>.</para></listitem>
<listitem><para>Additionally, <command>systemd-resolved</command> provides a local DNS stub listener on
<filename>/etc/systemd/resolved.conf</filename>, the per-link static settings in
<filename>/etc/systemd/network/*.network</filename> files (in case
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- is used), the per-link dynamic settings received over DHCP, user request made via
+ is used), the per-link dynamic settings received over DHCP, information provided via
<citerefentry><refentrytitle>resolvectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, and any
DNS server information made available by other system services. See
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> and
<listitem><para>The mappings defined in <filename>/etc/hosts</filename> are resolved to their
configured addresses and back, but they will not affect lookups for non-address types (like MX).
+ Support for <filename>/etc/hosts</filename> may be disabled with <varname>ReadEtcHosts=no</varname>,
+ see <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>Protocols and Routing</title>
- <para>Lookup requests are routed to the available DNS servers, LLMNR and MulticastDNS interfaces
+ <para>Lookup requests are routed to the available DNS servers, LLMNR, and MulticastDNS interfaces
according to the following rules:</para>
<itemizedlist>
- <listitem><para>Lookups for the special hostname <literal>localhost</literal> are never routed to the
- network. (A few other, special domains are handled the same way.)</para></listitem>
-
- <listitem><para>Single-label names are routed to all local interfaces capable of IP multicasting, using
- the LLMNR protocol. Lookups for IPv4 addresses are only sent via LLMNR on IPv4, and lookups for IPv6
- addresses are only sent via LLMNR on IPv6. Lookups for the locally configured host name and the
- <literal>_gateway</literal> host name are never routed to LLMNR.</para></listitem>
+ <listitem><para>Names for which synthetic records are generated (as listed in the previous section) are
+ never routed to the network and a reply is sent immediately. In particular this means that lookups for
+ <literal>localhost</literal> are never routed to the network.</para></listitem>
+
+ <listitem><para>Single-label names are routed to all local interfaces capable of IP multicasting, where
+ LLMNR is not disabled, using the LLMNR protocol. Lookups for IPv4 addresses are only sent via LLMNR on
+ IPv4, and lookups for IPv6 addresses are only sent via LLMNR on IPv6. Lookups for the locally
+ configured hostname and the <literal>_gateway</literal> hostname are never routed to LLMNR.
+ </para></listitem>
<listitem><para>Multi-label names with the domain suffix <literal>.local</literal> are routed to all
- local interfaces capable of IP multicasting, using the MulticastDNS protocol. As with LLMNR IPv4
- address lookups are sent via IPv4 and IPv6 address lookups are sent via IPv6.</para></listitem>
+ local interfaces capable of IP multicasting, where MulticastDNS is not disabled, using the MulticastDNS
+ protocol. As with LLMNR, IPv4 address lookups are sent via IPv4 and IPv6 address lookups are sent via
+ IPv6.</para></listitem>
+
+ <listitem><para>Resolution of address records (A and AAAA) via unicast DNS (i.e. not LLMNR or
+ MulticastDNS) for non-synthesized single-label names is only allowed for non-top-level domains. This
+ means that such records can only be resolved when search domains are defined. For any interface which
+ defines search domains, such look-ups are routed to that interface, suffixed with each of the search
+ domains defined on that interface in turn. When global search domains are defined, such look-ups are
+ routed to all interfaces, suffixed by each of the global search domains in turn. The details of which
+ servers are queried and how the final reply is chosen are described below. Note that this means that
+ address queries for single-label names are never sent out to remote DNS servers, and if no search
+ domains are defined, resolution will fail.</para></listitem>
<listitem><para>Other multi-label names are routed to all local interfaces that have a DNS server
- configured, plus the globally configured DNS server if there is one. Address lookups from the
- link-local address range are never routed to DNS. Note that by default lookups for domains with the
- <literal>.local</literal> suffix are not routed to DNS servers, unless the domain is specified
- explicitly as routing or search domain for the DNS server and interface. This means that on networks
- where the <literal>.local</literal> domain is defined in a site-specific DNS server, explicit search or
- routing domains need to be configured to make lookups within this DNS domain work. Note that today it's
- generally recommended to avoid defining <literal>.local</literal> in a DNS server, as <ulink
- url="https://tools.ietf.org/html/rfc6762">RFC6762</ulink> reserves this domain for exclusive
+ configured, plus the globally configured DNS servers if there are any. Note that by default, lookups for
+ domains with the <literal>.local</literal> suffix are not routed to DNS servers, unless the domain is
+ specified explicitly as routing or search domain for the DNS server and interface. This means that on
+ networks where the <literal>.local</literal> domain is defined in a site-specific DNS server, explicit
+ search or routing domains need to be configured to make lookups within this DNS domain work. Note that
+ these days, it's generally recommended to avoid defining <literal>.local</literal> in a DNS server, as
+ <ulink url="https://tools.ietf.org/html/rfc6762">RFC6762</ulink> reserves this domain for exclusive
MulticastDNS use.</para></listitem>
+
+ <listitem><para>Address lookups are routed similarly to multi-label names, with the exception that
+ addresses from the link-local address range are never routed to unicast DNS and are only resolved using
+ LLMNR and MulticastDNS (when enabled).</para></listitem>
</itemizedlist>
<para>If lookups are routed to multiple interfaces, the first successful response is returned (thus
<itemizedlist>
<listitem><para>If a name to look up matches (that is: is equal to or has as suffix) any of the
- configured search or route-only domains of any link (or the globally configured DNS settings), the
+ configured search or route-only domains of any link (see
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+ or the globally configured DNS settings (see the discussion of <varname>Domains=</varname> in
+ <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
"best matching" search/route-only domain is determined: the matching one with the most labels. The
query is then sent to all DNS servers of any links or the globally configured DNS servers associated
with this "best matching" search/route-only domain. (Note that more than one link might have this same
"best matching" search/route-only domain configured, in which case the query is sent to all of them in
- parallel).</para></listitem>
+ parallel).</para>
+
+ <para>In case of single-label names, when search domains are defined, the same logic applies, except
+ that the name is first suffixed by the search domain.</para></listitem>
<listitem><para>If a query does not match any configured search/route-only domain (neither per-link nor
global), it is sent to all DNS servers that are configured on links with the "DNS default route" option
configured DNS domains for a link: if there's any route-only domain (not matching <literal>~.</literal>)
it defaults to false, otherwise to true.</para>
- <para>Effectively this means: in order to preferably route all DNS queries not explicitly matched by
- search/route-only domain configuration to a specific link, configure a <literal>~.</literal> route-only
- domain on it. This will ensure that other links will not be considered for the queries (unless they too
- carry such a route-only domain). In order to route all such DNS queries to a specific link only in case
- no other link is preferable, then set the "DNS default route" option for the link to true, and do not
- configure a <literal>~.</literal> route-only domain on it. Finally, in order to ensure that a specific
- link never receives any DNS traffic not matching any of its configured search/route-only domains, set the
- "DNS default route" option for it to false.</para>
+ <para>Effectively this means: in order to support single-label non-synthetized names, define appropriate
+ search domains. In order to preferably route all DNS queries not explicitly matched by search/route-only
+ domain configuration to a specific link, configure a <literal>~.</literal> route-only domain on it. This
+ will ensure that other links will not be considered for these queries (unless they too carry such a
+ route-only domain). In order to route all such DNS queries to a specific link only if no other link
+ is preferable, set the "DNS default route" option for the link to true and do not configure a
+ <literal>~.</literal> route-only domain on it. Finally, in order to ensure that a specific link never
+ receives any DNS traffic not matching any of its configured search/route-only domains, set the "DNS
+ default route" option for it to false.</para>
<para>See the <ulink url="https://www.freedesktop.org/wiki/Software/systemd/resolved">resolved D-Bus API
Documentation</ulink> for information about the APIs <filename>systemd-resolved</filename> provides.
<listitem><para>Sets the maximum number of simultaneous connections, defaults to 256.
If the limit of concurrent connections is reached further connections will be refused.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--exit-idle-time=</option></term>
+
+ <listitem><para>Sets the time before exiting when there are no connections, defaults to
+ <constant>infinity</constant>. Takes a unit-less value in seconds, or a time span value such
+ as <literal>5min 20s</literal>.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<refsect1>
<programlisting><![CDATA[# systemctl enable --now proxy-to-nginx.socket
$ curl http://localhost:80/]]></programlisting>
</example>
+ <para>If <filename>nginx.service</filename> has <varname>StopWhenUnneeded=</varname> set, then
+ passing <option>--exit-idle-time=</option> to <command>systemd-socket-proxyd</command> allows
+ both services to stop during idle periods.</para>
</refsect2>
<refsect2>
<title>Namespace Example</title>
<para>See
<citerefentry><refentrytitle>org.freedesktop.timedate1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for information about the D-Bus API.</para>
</refsect1>
<listitem><para>Takes a directory path as an argument. All paths will be prefixed with the given alternate
<replaceable>root</replaceable> path, including config search paths.</para>
- <para>Note that this option does not alter how the users and groups specified in the configuration files are
- resolved. With or without this option, users and groups are always resolved according to the host's user and
- group databases, any such databases stored under the specified root directories are not
- consulted.</para></listitem>
+ <para>When this option is used, the libc Name Service Switch (NSS) is bypassed for resolving users
+ and groups. Instead the files <filename>/etc/passwd</filename> and <filename>/etc/group</filename>
+ inside the alternate root are read directly. This means that users/groups not listed in these files
+ will not be resolved, i.e. LDAP NIS and other complex databases are not considered.</para></listitem>
</varlistentry>
<varlistentry>
<citerefentry project='man-pages'><refentrytitle>touch</refentrytitle><manvolnum>1</manvolnum></citerefentry>
on it.</para>
+ <para>Note that if the <varname>systemd.condition-needs-update=</varname> kernel command line option is
+ used it overrides the <varname>ConditionNeedsUpdate=</varname> unit condition checks. In that case
+ <filename>systemd-update-done.service</filename> will not reset the condition state until a follow-up
+ reboot where the kernel switch is not specified anymore.</para>
</refsect1>
<refsect1>
<listitem><para>Automount units acquire automatic <varname>Before=</varname> and
<varname>Conflicts=</varname> on <filename>umount.target</filename> in order to be stopped during
shutdown.</para></listitem>
+
+ <listitem><para>Automount units automatically gain an <varname>After=</varname> dependency
+ on <filename>local-fs-pre.target</filename>, and a <varname>Before=</varname> dependency on
+ <filename>local-fs.target</filename>.</para></listitem>
</itemizedlist>
</refsect2>
</refsect1>
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
-<refentry id="systemd.dnssd" conditional='ENABLE_RESOLVE'>
+<refentry id="systemd.dnssd"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ conditional='ENABLE_RESOLVE'>
<refentryinfo>
<title>systemd.dnssd</title>
<para>An instance name of the network service as defined in the section 4.1.1 of <ulink
url="https://tools.ietf.org/html/rfc6763">RFC 6763</ulink>, e.g. <literal>webserver</literal>.</para>
<para>The option supports simple specifier expansion. The following expansions are understood:</para>
- <table>
+ <table class='specifiers'>
<title>Specifiers available</title>
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
<colspec colname="spec" />
</row>
</thead>
<tbody>
- <row>
- <entry><literal>%m</literal></entry>
- <entry>Machine ID</entry>
- <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
- </row>
- <row>
- <entry><literal>%b</literal></entry>
- <entry>Boot ID</entry>
- <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
- </row>
- <row>
- <entry><literal>%H</literal></entry>
- <entry>Host name</entry>
- <entry>The hostname of the running system.</entry>
- </row>
- <row>
- <entry><literal>%v</literal></entry>
- <entry>Kernel release</entry>
- <entry>Identical to <command>uname -r</command> output.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="a"/>
+ <xi:include href="standard-specifiers.xml" xpointer="b"/>
+ <xi:include href="standard-specifiers.xml" xpointer="B"/>
+ <xi:include href="standard-specifiers.xml" xpointer="H"/>
+ <xi:include href="standard-specifiers.xml" xpointer="m"/>
+ <xi:include href="standard-specifiers.xml" xpointer="o"/>
+ <xi:include href="standard-specifiers.xml" xpointer="v"/>
+ <xi:include href="standard-specifiers.xml" xpointer="w"/>
+ <xi:include href="standard-specifiers.xml" xpointer="W"/>
+ <xi:include href="standard-specifiers.xml" xpointer="percent"/>
</tbody>
</tgroup>
</table>
will also gain an automatic <varname>After=</varname> dependency on
<citerefentry><refentrytitle>systemd-tmpfiles-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
- <listitem><para>Units whose standard output or error output is connected to <option>journal</option>,
- <option>syslog</option> or <option>kmsg</option> (or their combinations with console output, see below)
- automatically acquire dependencies of type <varname>After=</varname> on
+ <listitem><para>Units whose standard output or error output is connected to <option>journal</option> or
+ <option>kmsg</option> (or their combinations with console output, see below) automatically acquire
+ dependencies of type <varname>After=</varname> on
<filename>systemd-journald.socket</filename>.</para></listitem>
<listitem><para>Units using <varname>LogNamespace=</varname> will automatically gain ordering and
<term><varname>ProtectSystem=</varname></term>
<listitem><para>Takes a boolean argument or the special values <literal>full</literal> or
- <literal>strict</literal>. If true, mounts the <filename>/usr</filename> and <filename>/boot</filename>
- directories read-only for processes invoked by this unit. If set to <literal>full</literal>, the
- <filename>/etc</filename> directory is mounted read-only, too. If set to <literal>strict</literal> the entire
- file system hierarchy is mounted read-only, except for the API file system subtrees <filename>/dev</filename>,
+ <literal>strict</literal>. If true, mounts the <filename>/usr</filename> and the boot loader
+ directories (<filename>/boot</filename> and <filename>/efi</filename>) read-only for processes
+ invoked by this unit. If set to <literal>full</literal>, the <filename>/etc</filename> directory is
+ mounted read-only, too. If set to <literal>strict</literal> the entire file system hierarchy is
+ mounted read-only, except for the API file system subtrees <filename>/dev</filename>,
<filename>/proc</filename> and <filename>/sys</filename> (protect these directories using
<varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
<varname>ProtectControlGroups=</varname>). This setting ensures that any modification of the vendor-supplied
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>$LOG_NAMESPACE</varname></term>
+
+ <listitem><para>If the <varname>LogNamespace=</varname> service setting is used, contains name of the
+ selected logging namespace.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>$JOURNAL_STREAM</varname></term>
<varlistentry>
<term><varname>_LINE_BREAK=</varname></term>
<listitem>
- <para>Only applies to <literal>_TRANSPORT=stdout</literal> records: indicates that the log message in the
- standard output/error stream was not terminated with a normal newline character (<literal>\n</literal>,
- i.e. ASCII 10). Specifically, when set this field is one of <option>nul</option> (in case the line was
- terminated by a NUL byte), <option>line-max</option> (in case the maximum log line length was reached, as
- configured with <varname>LineMax=</varname> in
- <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or
- <option>eof</option> (if this was the last log record of a stream and the stream ended without a final
- newline character). Note that this record is not generated when a normal newline character was used for
- marking the log line end.</para>
+ <para>Only applies to <literal>_TRANSPORT=stdout</literal> records: indicates that the log message
+ in the standard output/error stream was not terminated with a normal newline character
+ (<literal>\n</literal>, i.e. ASCII 10). Specifically, when set this field is one of
+ <option>nul</option> (in case the line was terminated by a NUL byte), <option>line-max</option> (in
+ case the maximum log line length was reached, as configured with <varname>LineMax=</varname> in
+ <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+ <option>eof</option> (if this was the last log record of a stream and the stream ended without a
+ final newline character), or <option>pid-change</option> (if the process which generated the log
+ output changed in the middle of a line). Note that this record is not generated when a normal
+ newline character was used for marking the log line end.</para>
</listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>RxBufferSize=</varname></term>
<listitem>
- <para>Takes a integer. Specifies the NIC receive ring buffer size. When unset, the kernel's default will be used.</para>
+ <para>Takes an integer. Specifies the maximum number of pending packets in the NIC receive buffer.
+ When unset, the kernel's default will be used.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>RxMiniBufferSize=</varname></term>
+ <listitem>
+ <para>Takes an integer. Specifies the maximum number of pending packets in the NIC mini receive buffer.
+ When unset, the kernel's default will be used.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>RxJumboBufferSize=</varname></term>
+ <listitem>
+ <para>Takes an integer. Specifies the maximum number of pending packets in the NIC jumbo receive buffer.
+ When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TxBufferSize=</varname></term>
<listitem>
- <para>Takes a integer. Specifies the NIC transmit ring buffer size. When unset, the kernel's default will be used.</para>
+ <para>Takes an integer. Specifies the maximum number of pending packets in the NIC transmit buffer.
+ When unset, the kernel's default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<varname>Options=</varname> setting in a unit file.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>x-systemd.rw-only</option></term>
+
+ <listitem><para>If a mount operation fails to mount the file system
+ read-write, it normally tries mounting the file system read-only instead.
+ This option disables that behaviour, and causes the mount to fail
+ immediately instead. This option is translated into the
+ <varname>ReadWriteOnly=</varname> setting in a unit file.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>_netdev</option></term>
created. (See
<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more information.) This option is mandatory. Note that the usual specifier expansion is applied
- to this setting, literal percent characters should hence be written as <literal>%%</literal>. If this
- mount is a bind mount and the specified path does not exist yet it is created as
- directory.</para></listitem>
+ to this setting, literal percent characters should hence be written as <literal
+ class='specifiers'>%%</literal>. If this mount is a bind mount and the specified path does not exist
+ yet it is created as directory.</para></listitem>
</varlistentry>
<varlistentry>
<listitem><para>Mount options to use when mounting. This takes a comma-separated list of options. This setting
is optional. Note that the usual specifier expansion is applied to this setting, literal percent characters
- should hence be written as <literal>%%</literal>.</para></listitem>
+ should hence be written as <literal class='specifiers'>%%</literal>.</para></listitem>
</varlistentry>
<varlistentry>
off.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ReadWriteOnly=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If false, a mount
+ point that shall be mounted read-write but cannot be mounted
+ so is retried to be mounted read-only. If true the operation
+ will fail immediately after the read-write mount attempt did
+ not succeed. This corresponds with
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+ <parameter>-w</parameter> switch. Defaults to
+ off.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>ForceUnmount=</varname></term>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>VLANProtocol=</varname></term>
+ <listitem>
+ <para>Allows setting the protocol used for VLAN filtering. Takes
+ <option>802.1q</option> or,
+ <option>802.1ad</option>, and defaults to unset and kernel's default is used.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>STP=</varname></term>
<listitem>
controlled by other applications.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>Group=</varname></term>
+ <listitem>
+ <para>Link groups are similar to port ranges found in managed switches.
+ When network interfaces are added to a numbered group, operations on
+ all the interfaces from that group can be performed at once. An unsigned
+ integer ranges 0 to 4294967294. Default to unset.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>RequiredForOnline=</varname></term>
<listitem>
<literal>nearest-bridge</literal>, <literal>non-tpmr-bridge</literal> and
<literal>customer-bridge</literal>. Defaults to false, which turns off LLDP packet emission. If not false,
a short LLDP packet with information about the local system is sent out in regular intervals on the
- link. The LLDP packet will contain information about the local host name, the local machine ID (as stored
+ link. The LLDP packet will contain information about the local hostname, the local machine ID (as stored
in <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>) and the
local interface name, as well as the pretty hostname of the system (as set in
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>). LLDP
this link. Each item in the list should be a domain name, optionally prefixed with a tilde
(<literal>~</literal>). The domains with the prefix are called "routing-only domains". The
domains without the prefix are called "search domains" and are first used as search suffixes for
- extending single-label host names (host names containing no dots) to become fully qualified
- domain names (FQDNs). If a single-label host name is resolved on this interface, each of the
+ extending single-label hostnames (hostnames containing no dots) to become fully qualified
+ domain names (FQDNs). If a single-label hostname is resolved on this interface, each of the
specified search domains are appended to it in turn, converting it into a fully qualified domain
name, until one of them may be successfully resolved.</para>
- <para>Both "search" and "routing-only" domains are used for routing of DNS queries: look-ups for host names
+ <para>Both "search" and "routing-only" domains are used for routing of DNS queries: look-ups for hostnames
ending in those domains (hence also single label names, if any "search domains" are listed), are routed to
the DNS servers configured for this interface. The domain routing logic is particularly useful on
multi-homed hosts with DNS servers serving particular private DNS zones on each interface.</para>
false.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
- of all host names, in particular of single-label names. It is generally safer to use the supplied domain
+ of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>FallbackLeaseLifetimeSec=</varname></term>
+ <listitem>
+ <para>Allows to set DHCPv4 lease lifetime when DHCPv4 server does not send the lease lifetime.
+ Takes one of <literal>forever</literal> or <literal>infinity</literal> means that the address
+ never expires. Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>SendRelease=</varname></term>
<listitem>
<varlistentry>
<term><varname>RequestOptions=</varname></term>
<listitem>
- <para>A whitespace-separated list of integers in the range 1–254.</para>
+ <para>When configured, allows to set arbitrary request options in the DHCPv4 request options list and will be
+ sent to the DHCPV4 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RequestOptions=</varname></term>
+ <listitem>
+ <para>When configured, allows to set arbitrary request options in the DHCPv6 request options list and will
+ sent to the DHCPV6 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
<listitem>
<listitem>
<para>Takes an IPv6 address with prefix length as <varname>Address=</varname> in
the "[Network]" section. Specifies the DHCPv6 client for the requesting router to include
- a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1-128. Defaults to unset.</para>
+ a prefix-hint in the DHCPv6 solicitation. Prefix ranges 1..128. Defaults to unset.</para>
</listitem>
</varlistentry>
Defaults to false.</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>SendOption=</varname></term>
+ <listitem>
+ <para>As in the <literal>[DHCPv4]</literal> section, however because DHCPv6 uses 16-bit fields to store
+ option numbers, the option number is an integer in the range 1..65536.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>UserClass=</varname></term>
+ <listitem>
+ <para>A DHCPv6 client can use User Class option to identify the type or category of user or applications
+ it represents. The information contained in this option is a string that represents the user class of which
+ the client is a member. Each class sets an identifying string of information to be used by the DHCP
+ service to classify clients. Special characters in the data string may be escaped using
+ <ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
+ escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
+ then all options specified earlier are cleared. Takes a whitespace-separated list of strings. Note that
+ currently NUL bytes are not allowed.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>VendorClass=</varname></term>
+ <listitem>
+ <para>A DHCPv6 client can use VendorClass option to identify the vendor that
+ manufactured the hardware on which the client is running. The information
+ contained in the data area of this option is contained in one or more opaque
+ fields that identify details of the hardware configuration. Takes a
+ whitespace-separated list of strings.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<literal>~</literal>. Defaults to false.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
- of all host names, in particular of single-label names. It is generally safer to use the supplied domain
+ of all hostnames, in particular of single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
<para>Send a raw option with value via DHCPv4 server. Takes a DHCP option number, data type
and data (<literal><replaceable>option</replaceable>:<replaceable>type</replaceable>:<replaceable>value</replaceable></literal>).
The option number is an integer in the range 1..254. The type takes one of <literal>uint8</literal>,
- <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or
+ <literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, <literal>ipv6address</literal>, or
<literal>string</literal>. Special characters in the data string may be escaped using
<ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
escapes</ulink>. This setting can be specified multiple times. If an empty string is specified,
<varlistentry>
<term><varname>SuccessExitStatus=</varname></term>
+
<listitem><para>Takes a list of exit status definitions that, when returned by the main service
- process, will be considered successful termination, in addition to the normal successful exit code 0
- and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
+ process, will be considered successful termination, in addition to the normal successful exit status
+ 0 and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>,
<constant>SIGTERM</constant>, and <constant>SIGPIPE</constant>. Exit status definitions can be
- numeric exit codes, termination code names, or termination signal names, separated by spaces. See the
- Process Exit Codes section in
+ numeric termination statuses, termination status names, or termination signal names, separated by
+ spaces. See the Process Exit Codes section in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
- a list of termination codes names (for this setting only the part without the
- <literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See
- <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+ a list of termination status names (for this setting only the part without the
+ <literal>EXIT_</literal> or <literal>EX_</literal> prefix should be used). See <citerefentry
+ project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
a list of signal names.</para>
- <para>This option may appear more than once, in which case the
- list of successful exit statuses is merged. If the empty
- string is assigned to this option, the list is reset, all
- prior assignments of this option will have no
- effect.</para>
+ <para>Note that this setting does not change the the mapping between numeric exit statuses and their
+ names, i.e. regardless how this setting is used 0 will still be mapped to <literal>SUCCESS</literal>
+ (and thus typically shown as <literal>0/SUCCESS</literal> in tool outputs) and 1 to
+ <literal>FAILURE</literal> (and thus typically shown as <literal>1/FAILURE</literal>), and so on. It
+ only controls what happens as effect of these exit statuses, and how it propagates to the state of
+ the service as a whole.</para>
+
+ <para>This option may appear more than once, in which case the list of successful exit statuses is
+ merged. If the empty string is assigned to this option, the list is reset, all prior assignments of
+ this option will have no effect.</para>
<example>
<title>A service with with the <varname>SuccessExitStatus=</varname> setting</title>
<programlisting>SuccessExitStatus=TEMPFAIL 250 SIGUSR1</programlisting>
- <para>Exit codes 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
+ <para>Exit status 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
<constant>SIGKILL</constant> are considered clean service terminations.</para>
</example>
- <para>Note: <command>systemd-analyze exit-codes</command> may be used to list exit
- codes and translate between numerical code values and names.</para></listitem>
+ <para>Note: <command>systemd-analyze exit-status</command> may be used to list exit statuses and
+ translate between numerical status values and names.</para></listitem>
</varlistentry>
<varlistentry>
<option>exec</option>. Conversely, if an auxiliary process of the unit sends an
<function>sd_notify()</function> message and immediately exits, the service manager might not be able to
properly attribute the message to the unit, and thus will ignore it, even if
- <varname>NotifyAccess=</varname><option>all</option> is set for it.</para></listitem>
+ <varname>NotifyAccess=</varname><option>all</option> is set for it.</para>
+
+ <para>Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of notifications
+ to units correctly, <function>sd_notify_barrier()</function> may be used. This call acts as a synchronization point
+ and ensures all notifications sent before this call have been picked up by the service manager when it returns
+ successfully. Use of <function>sd_notify_barrier()</function> is needed for clients which are not invoked by the
+ service manager, otherwise this synchronization mechanism is unnecessary for attribution of notifications to the
+ unit.</para></listitem>
</varlistentry>
<varlistentry>
project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
details. If this refers to a device node, a dependency on the respective device unit is automatically
created. (See
- <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more
- information.) If this refers to a file, a dependency on the respective mount unit is automatically
- created. (See <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for more information.) This option is mandatory. Note that the usual specifier expansion is applied to this
- setting, literal percent characters should hence be written as <literal>%%</literal>.</para></listitem>
+ <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for more information.) If this refers to a file, a dependency on the respective mount unit is
+ automatically created. (See
+ <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ more information.) This option is mandatory. Note that the usual specifier expansion is applied to
+ this setting, literal percent characters should hence be written as
+ <literal class='specifiers'>%%</literal>.</para></listitem>
</varlistentry>
<varlistentry>
continuous weekdays. <literal>,</literal> and <literal>..</literal>
may be combined freely.</para>
- <para>In the date and time specifications, any component may be
- specified as <literal>*</literal> in which case any value will
- match. Alternatively, each component can be specified as a list of
- values separated by commas. Values may be suffixed with
- <literal>/</literal> and a repetition value, which indicates that
- the value itself and the value plus all multiples of the repetition value
- are matched. Two values separated by <literal>..</literal> may be used
- to indicate a range of values; ranges may also be followed with
- <literal>/</literal> and a repetition value.</para>
+ <para>In the date and time specifications, any component may be specified as <literal>*</literal> in
+ which case any value will match. Alternatively, each component can be specified as a list of values
+ separated by commas. Values may be suffixed with <literal>/</literal> and a repetition value, which
+ indicates that the value itself and the value plus all multiples of the repetition value are matched.
+ Two values separated by <literal>..</literal> may be used to indicate a range of values; ranges may also
+ be followed with <literal>/</literal> and a repetition value, in which case the expression matches all
+ times starting with the start value, and continuing with all multiples of the repetition value relative
+ to the start value, ending at the end value the latest.</para>
<para>A date specification may use <literal>~</literal> to indicate the
last day(s) in a month. For example, <literal>*-02~03</literal> means
]>
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
-<refentry id="systemd.unit">
+<refentry id="systemd.unit"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd.unit</title>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ConditionEnvironment=</varname></term>
+
+ <listitem><para><varname>ConditionEnvironment=</varname> may be used to check whether a specific
+ environment variable is set (or if prefixed with the exclamation mark — unset) in the service
+ manager's environment block.
+
+ The argument may be a single word, to check if the variable with this name is defined in the
+ environment block, or an assignment
+ (<literal><replaceable>name</replaceable>=<replaceable>value</replaceable></literal>), to check if
+ the variable with this exact value is defined. Note that the environment block of the service
+ manager itself is checked, i.e. not any variables defined with <varname>Environment=</varname> or
+ <varname>EnvironmentFile=</varname>, as described above. This is particularly useful when the
+ service manager runs inside a containerized environment or as per-user service manager, in order to
+ check for variables passed in by the enclosing container manager or PAM.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>ConditionSecurity=</varname></term>
<citerefentry><refentrytitle>systemd-update-done.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
to make sure they run before the stamp file's modification time gets reset indicating a completed
update.</para>
+
+ <para>If the <varname>systemd.condition-needs-update=</varname> option is specified on the kernel
+ command line (taking a boolean), it will override the result of this condition check, taking
+ precedence over any file modification time checks. If it is used
+ <filename>systemd-update-done.service</filename> will not have immediate effect on any following
+ <varname>ConditionNeedsUpdate=</varname> checks, until the system is rebooted where the kernel
+ command line option is not specified anymore.</para>
</listitem>
</varlistentry>
(specifically: an <filename>/etc</filename> with no <filename>/etc/machine-id</filename>). This may
be used to populate <filename>/etc</filename> on the first boot after factory reset, or when a new
system instance boots up for the first time.</para>
+
+ <para>If the <varname>systemd.condition-first-boot=</varname> option is specified on the kernel
+ command line (taking a boolean), it will override the result of this condition check, taking
+ precedence over <filename>/etc/machine-id</filename> existence checks.</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ConditionPathIsEncrypted=</varname></term>
+
+ <listitem><para><varname>ConditionPathIsEncrypted=</varname> is similar to
+ <varname>ConditionPathExists=</varname> but verifies that the underlying file system's backing
+ block device is encrypted using dm-crypt/LUKS. Note that this check does not cover ext4
+ per-directory encryption, and only detects block level encryption. Moreover, if the specified path
+ resides on a file system on top of a loopback block device, only encryption above the loopback device is
+ detected. It is not detected whether the file system backing the loopback block device is encrypted.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
and resolvable for the setting to be valid. The following
specifiers are understood:</para>
- <table>
+ <table class='specifiers'>
<title>Specifiers available in unit files</title>
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
<colspec colname="spec" />
</thead>
<tbody>
<row>
- <entry><literal>%b</literal></entry>
- <entry>Boot ID</entry>
- <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
+ <!-- We do not use the common definition from standard-specifiers.xml here since it includes a
+ reference onto our own man page, which would make the rendered version self-referential. -->
+ <entry><literal>%a</literal></entry>
+ <entry>Architecture</entry>
+ <entry>A short string identifying the architecture of the local system. A string such as <constant>x86</constant>, <constant>x86-64</constant> or <constant>arm64</constant>. See the architectures defined for <varname>ConditionArchitecture=</varname> above for a full list.</entry>
</row>
+ <xi:include href="standard-specifiers.xml" xpointer="b"/>
+ <xi:include href="standard-specifiers.xml" xpointer="B"/>
<row>
<entry><literal>%C</literal></entry>
<entry>Cache directory root</entry>
Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry>
</row>
<row>
+ <!-- We do not use the common definition from standard-specifiers.xml here since we want a
+ slightly more verbose explanation here, referring to the reload cycle. -->
<entry><literal>%H</literal></entry>
<entry>Host name</entry>
<entry>The hostname of the running system at the point in time the unit configuration is loaded.</entry>
</row>
+ <row>
+ <entry><literal>%l</literal></entry>
+ <entry>Short host name</entry>
+ <entry>The hostname of the running system at the point in time the unit configuration is loaded, truncated at the first dot to remove any domain component.</entry>
+ </row>
<row>
<entry><literal>%i</literal></entry>
<entry>Instance name</entry>
<entry>Log directory root</entry>
<entry>This is either <filename>/var/log</filename> (for the system manager) or the path <literal>$XDG_CONFIG_HOME</literal> resolves to with <filename index="false">/log</filename> appended (for user managers).</entry>
</row>
- <row>
- <entry><literal>%m</literal></entry>
- <entry>Machine ID</entry>
- <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="m"/>
+ <xi:include href="standard-specifiers.xml" xpointer="o"/>
<row>
<entry><literal>%n</literal></entry>
<entry>Full unit name</entry>
Note that this setting is <emphasis>not</emphasis> influenced by the <varname>User=</varname> setting configurable in the [Service] section of the service unit.</entry>
</row>
- <row>
- <entry><literal>%v</literal></entry>
- <entry>Kernel release</entry>
- <entry>Identical to <command>uname -r</command> output</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="v"/>
<row>
<entry><literal>%V</literal></entry>
<entry>Directory for larger and persistent temporary files</entry>
<entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
</row>
- <row>
- <entry><literal>%%</literal></entry>
- <entry>Single percent sign</entry>
- <entry>Use <literal>%%</literal> in place of <literal>%</literal> to specify a single percent sign.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="w"/>
+ <xi:include href="standard-specifiers.xml" xpointer="W"/>
+ <xi:include href="standard-specifiers.xml" xpointer="percent"/>
</tbody>
</tgroup>
</table>
execution compared to the target unit's state and is marked successful and
complete when both satisfy. However, this job also pulls in other
dependencies due to the defined relationships and thus leads to, in our
- our example, start jobs for any of those inactive units getting queued as
+ example, start jobs for any of those inactive units getting queued as
well.</para>
<para>systemd contains native implementations of various tasks
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<para>The D-Bus API of <command>systemd</command> is described in
- <citerefentry><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ <citerefentry><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and
+ <citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
<para>Systems which invoke systemd in a container or initrd environment should implement the <ulink
url="https://systemd.io/CONTAINER_INTERFACE">Container Interface</ulink> or <ulink
<refsect1>
<title>Specifiers</title>
- <para>Specifiers can be used in the "Name", "ID", "GECOS", "Home directory", and "Shell" fields.
- An unknown or unresolvable specifier is treated as invalid configuration.
- The following expansions are understood:</para>
- <table>
- <title>Specifiers available</title>
- <tgroup cols='3' align='left' colsep='1' rowsep='1'>
- <colspec colname="spec" />
- <colspec colname="mean" />
- <colspec colname="detail" />
- <thead>
- <row>
- <entry>Specifier</entry>
- <entry>Meaning</entry>
- <entry>Details</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>%b</literal></entry>
- <entry>Boot ID</entry>
- <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
- </row>
- <row>
- <entry><literal>%H</literal></entry>
- <entry>Host name</entry>
- <entry>The hostname of the running system.</entry>
- </row>
- <row>
- <entry><literal>%m</literal></entry>
- <entry>Machine ID</entry>
- <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
- </row>
- <row>
- <entry><literal>%T</literal></entry>
- <entry>Directory for temporary files</entry>
- <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
- </row>
- <row>
- <entry><literal>%v</literal></entry>
- <entry>Kernel release</entry>
- <entry>Identical to <command>uname -r</command> output.</entry>
- </row>
- <row>
- <entry><literal>%V</literal></entry>
- <entry>Directory for larger and persistent temporary files</entry>
- <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
- </row>
- <row>
- <entry><literal>%%</literal></entry>
- <entry>Escaped <literal>%</literal></entry>
- <entry>Single percent sign.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <para>Specifiers can be used in the <literal>Name</literal>, <literal>ID</literal>,
+ <literal>GECOS</literal>, <literal>Home directory</literal>, and <literal>Shell</literal> fields. An
+ unknown or unresolvable specifier is treated as invalid configuration. The following expansions are
+ understood:</para>
+
+ <table class='specifiers'>
+ <title>Specifiers available</title>
+ <tgroup cols='3' align='left' colsep='1' rowsep='1'>
+ <colspec colname="spec" />
+ <colspec colname="mean" />
+ <colspec colname="detail" />
+ <thead>
+ <row>
+ <entry>Specifier</entry>
+ <entry>Meaning</entry>
+ <entry>Details</entry>
+ </row>
+ </thead>
+ <tbody>
+ <xi:include href="standard-specifiers.xml" xpointer="a"/>
+ <xi:include href="standard-specifiers.xml" xpointer="b"/>
+ <xi:include href="standard-specifiers.xml" xpointer="B"/>
+ <xi:include href="standard-specifiers.xml" xpointer="H"/>
+ <xi:include href="standard-specifiers.xml" xpointer="l"/>
+ <xi:include href="standard-specifiers.xml" xpointer="m"/>
+ <xi:include href="standard-specifiers.xml" xpointer="o"/>
+ <row>
+ <entry><literal>%T</literal></entry>
+ <entry>Directory for temporary files</entry>
+ <entry>This is either <filename>/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
+ </row>
+ <xi:include href="standard-specifiers.xml" xpointer="v"/>
+ <row>
+ <entry><literal>%V</literal></entry>
+ <entry>Directory for larger and persistent temporary files</entry>
+ <entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
+ </row>
+ <xi:include href="standard-specifiers.xml" xpointer="w"/>
+ <xi:include href="standard-specifiers.xml" xpointer="W"/>
+ <xi:include href="standard-specifiers.xml" xpointer="percent"/>
+ </tbody>
+ </tgroup>
+ </table>
</refsect1>
<refsect1>
Copyright © 2010 Brandon Philips
-->
-<refentry id="tmpfiles.d">
+<refentry id="tmpfiles.d"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>tmpfiles.d</title>
<filename>/usr/lib/tmpfiles.d</filename> and <filename>/run/tmpfiles.d</filename>. Files in
<filename>/run/tmpfiles.d</filename> override files with the same name in
<filename>/usr/lib/tmpfiles.d</filename>. Packages should install their configuration files in
- <filename>/usr/lib/tmpfiles.d</filename>. Files in <filename>/etc/tmpfiles.d</filename> are reserved for the local
- administrator, who may use this logic to override the configuration files installed by vendor packages. All
- configuration files are sorted by their filename in lexicographic order, regardless of which of the directories
- they reside in. If multiple files specify the same path, the entry in the file with the lexicographically earliest
- name will be applied. All other conflicting entries will be logged as errors. When two lines are prefix path and
- suffix path of each other, then the prefix line is always created first, the suffix later (and if removal applies
- to the line, the order is reversed: the suffix is removed first, the prefix later). Lines that take globs are
- applied after those accepting no globs. If multiple operations shall be applied on the same file (such as ACL,
- xattr, file attribute adjustments), these are always done in the same fixed order. Except for those cases, the
- files/directories are processed in the order they are listed.</para>
+ <filename>/usr/lib/tmpfiles.d</filename>. Files in <filename>/etc/tmpfiles.d</filename> are reserved for
+ the local administrator, who may use this logic to override the configuration files installed by vendor
+ packages. All configuration files are sorted by their filename in lexicographic order, regardless of
+ which of the directories they reside in. If multiple files specify the same path, the entry in the file
+ with the lexicographically earliest name will be applied (note that lines suppressed due to the
+ <literal>!</literal> are filtered before application, meaning that if an early line carries the
+ exclamation mark and is suppressed because of that, a later line matching in path will be applied). All
+ other conflicting entries will be logged as errors. When two lines are prefix path and suffix path of
+ each other, then the prefix line is always created first, the suffix later (and if removal applies to the
+ line, the order is reversed: the suffix is removed first, the prefix later). Lines that take globs are
+ applied after those accepting no globs. If multiple operations shall be applied on the same file (such as
+ ACL, xattr, file attribute adjustments), these are always done in the same fixed order. Except for those
+ cases, the files/directories are processed in the order they are listed.</para>
<para>If the administrator wants to disable a configuration file
supplied by the vendor, the recommended way is to place a symlink
<refsect2>
<title>Type</title>
- <para>The type consists of a single letter and optionally an
- exclamation mark and/or minus sign.</para>
+ <para>The type consists of a single letter and optionally an exclamation mark (<literal>!</literal>)
+ and/or minus sign (<literal>-</literal>).</para>
<para>The following line types are understood:</para>
</varlistentry>
</variablelist>
- <para>If the exclamation mark is used, this line is only safe to
- execute during boot, and can break a running system. Lines
- without the exclamation mark are presumed to be safe to execute
- at any time, e.g. on package upgrades.
- <command>systemd-tmpfiles</command> will execute line with an
- exclamation mark only if option <option>--boot</option> is
- given.</para>
+ <para>If the exclamation mark (<literal>!</literal>) is used, this line is only safe to execute during
+ boot, and can break a running system. Lines without the exclamation mark are presumed to be safe to
+ execute at any time, e.g. on package upgrades. <command>systemd-tmpfiles</command> will take lines with
+ an exclamation mark only into consideration, if the <option>--boot</option> option is given.</para>
<para>For example:
<programlisting># Make sure these are created by default so that nobody else can
running system, and will only be executed with
<option>--boot</option>.</para>
- <para>If the minus sign is used, this line failing to run
- successfully during create (and only create) will not cause
- the execution of <command>systemd-tmpfiles</command> to return
+ <para>If the minus sign (<literal>-</literal>) is used, this line failing to run successfully during
+ create (and only create) will not cause the execution of <command>systemd-tmpfiles</command> to return
an error.</para>
<para>For example:
<para>Specifiers can be used in the "path" and "argument" fields.
An unknown or unresolvable specifier is treated as invalid configuration.
The following expansions are understood:</para>
- <table>
+ <table class='specifiers'>
<title>Specifiers available</title>
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
<colspec colname="spec" />
</row>
</thead>
<tbody>
- <row>
- <entry><literal>%b</literal></entry>
- <entry>Boot ID</entry>
- <entry>The boot ID of the running system, formatted as string. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for more information.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="a"/>
+ <xi:include href="standard-specifiers.xml" xpointer="b"/>
+ <xi:include href="standard-specifiers.xml" xpointer="B"/>
<row>
<entry><literal>%C</literal></entry>
<entry>System or user cache directory</entry>
<entry>User home directory</entry>
<entry>This is the home directory of the user running the command. In case of the system instance this resolves to <literal>/root</literal>.</entry>
</row>
- <row>
- <entry><literal>%H</literal></entry>
- <entry>Host name</entry>
- <entry>The hostname of the running system.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="H"/>
+ <xi:include href="standard-specifiers.xml" xpointer="l"/>
<row>
<entry><literal>%L</literal></entry>
<entry>System or user log directory</entry>
<entry>In <option>--user</option> mode, this is the same as <varname>$XDG_CONFIG_HOME</varname> with <filename index="false">/log</filename> appended, and <filename>/var/log</filename> otherwise.</entry>
</row>
- <row>
- <entry><literal>%m</literal></entry>
- <entry>Machine ID</entry>
- <entry>The machine ID of the running system, formatted as string. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="m"/>
+ <xi:include href="standard-specifiers.xml" xpointer="o"/>
<row>
<entry><literal>%S</literal></entry>
<entry>System or user state directory</entry>
<entry>User UID</entry>
<entry>This is the numeric UID of the user running the command. In case of the system instance this resolves to <constant>0</constant>.</entry>
</row>
- <row>
- <entry><literal>%v</literal></entry>
- <entry>Kernel release</entry>
- <entry>Identical to <command>uname -r</command> output.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="v"/>
<row>
<entry><literal>%V</literal></entry>
<entry>Directory for larger and persistent temporary files</entry>
<entry>This is either <filename>/var/tmp</filename> or the path <literal>$TMPDIR</literal>, <literal>$TEMP</literal> or <literal>$TMP</literal> are set to.</entry>
</row>
- <row>
- <entry><literal>%%</literal></entry>
- <entry>Escaped <literal>%</literal></entry>
- <entry>Single percent sign.</entry>
- </row>
+ <xi:include href="standard-specifiers.xml" xpointer="w"/>
+ <xi:include href="standard-specifiers.xml" xpointer="W"/>
+ <xi:include href="standard-specifiers.xml" xpointer="percent"/>
</tbody>
</tgroup>
</table>
"s", SD_BUS_PARAM(returnstring),
method, offsetof(object, number),
SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_METHOD_WITH_ARGS_OFFSET(
+ "Method3",
+ SD_BUS_ARGS("s", string, "o", path),
+ SD_BUS_RESULT("s", returnstring),
+ method, offsetof(object, number),
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS(
+ "Method4",
+ SD_BUS_NO_ARGS,
+ SD_BUS_NO_RESULT,
+ method,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_SIGNAL(
+ "Signal1",
+ "so",
+ 0),
+ SD_BUS_SIGNAL_WITH_NAMES(
+ "Signal2",
+ "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+ 0),
+ SD_BUS_SIGNAL_WITH_ARGS(
+ "Signal3",
+ SD_BUS_ARGS("s", string, "o", path),
+ 0),
SD_BUS_WRITABLE_PROPERTY(
"AutomaticStringProperty", "s", NULL, NULL,
offsetof(object, name),
base64 < plaintext.bin | tr -d '\n\r\t ' > plaintext.base64
# Encrypt this newly generated (binary) LUKS decryption key using the public key whose private key is on the
-# Yubikey, store the result in /etc/encrypted-luks-key.bin, where we'll look for it during boot.
-sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/encrypted-luks-key.bin
+# Yubikey, store the result in /etc/cryptsetup-keys.d/mytest.key, where we'll look for it during boot.
+mkdir -p /etc/cryptsetup-keys.d
+sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/cryptsetup-keys.d/mytest.key
# Configure the LUKS decryption key on the LUKS device. We use very low pbkdf settings since the key already
# has quite a high quality (it comes directly from /dev/urandom after all), and thus we don't need to do much
rm pubkey.pem
# Test: Let's run systemd-cryptsetup to test if this all worked. The option string should contain the full
-# PKCS#11 URI we have in the clipboard, it tells the tool how to decipher the encrypted LUKS key.
-sudo systemd-cryptsetup attach mytest /dev/sdXn /etc/encrypted-luks-key.bin 'pkcs11-uri=pkcs11:…'
+# PKCS#11 URI we have in the clipboard; it tells the tool how to decipher the encrypted LUKS key. Note that
+# systemd-cryptsetup automatically searches for the encrypted key in /etc/cryptsetup-keys.d/, hence we do
+# not need to specify the key file path explicitly here.
+sudo systemd-cryptsetup attach mytest /dev/sdXn - 'pkcs11-uri=pkcs11:…'
# If that worked, let's now add the same line persistently to /etc/crypttab, for the future.
-sudo bash -c 'echo "mytest /dev/sdXn /etc/encrypted-luks-key \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'
+sudo bash -c 'echo "mytest /dev/sdXn - \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'
# This is to be used instead of meson.source_root(), as the latter will return
# the wrong result when systemd is being built as a meson subproject
project_source_root = meson.current_source_dir()
+project_build_root = meson.current_build_dir()
relative_source_path = run_command('realpath',
- '--relative-to=@0@'.format(meson.current_build_dir()),
+ '--relative-to=@0@'.format(project_build_root),
project_source_root).stdout().strip()
conf.set_quoted('RELATIVE_SOURCE_PATH', relative_source_path)
conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
description : 'SysV init scripts and rcN.d links are supported')
+if get_option('hibernate') and not get_option('initrd')
+ error('hibernate depends on initrd')
+endif
+
conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max'))
conf.set10('BUMP_PROC_SYS_FS_NR_OPEN', get_option('bump-proc-sys-fs-nr-open'))
conf.set('HIGH_RLIMIT_NOFILE', 512*1024)
substs.set('MEMORY_ACCOUNTING_DEFAULT', memory_accounting_default ? 'yes' : 'no')
substs.set('STATUS_UNIT_FORMAT_DEFAULT', status_unit_format_default)
substs.set('HIGH_RLIMIT_NOFILE', conf.get('HIGH_RLIMIT_NOFILE'))
-substs.set('BUILD_ROOT', meson.current_build_dir())
+substs.set('BUILD_ROOT', project_build_root)
#####################################################################
cc = meson.get_compiler('c')
pkgconfig = import('pkgconfig')
-check_compilation_sh = find_program('tools/meson-check-compilation.sh')
+check_compilation_sh = find_program('tools/check-compilation.sh')
meson_build_sh = find_program('tools/meson-build.sh')
want_tests = get_option('tests')
'-Wno-unused-result',
'-Wno-format-signedness',
]
-if get_option('b_ndebug') == 'true'
- # With asserts disabled with get a bunch of warnings about variables which
- # are used only in the asserts. This is not useful at all, so let's just silence
- # those warnings.
- basic_disabled_warnings += [
- '-Wno-unused-variable',
- '-Wno-unused-but-set-variable',
- ]
-endif
possible_cc_flags = [
'-Werror=undef',
'-Wno-error=#warnings', # clang
'-Wno-string-plus-int', # clang
- # work-around for gcc 7.1 turning this on on its own.
- '-Wno-error=nonnull',
-
# Disable -Wmaybe-uninitialized, since it's noisy on gcc 8 with
# optimizations enabled, producing essentially false positives.
'-Wno-maybe-uninitialized',
add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')
add_project_link_arguments(cc.get_supported_link_arguments(possible_link_flags), language : 'c')
+have = cc.has_argument('-Wzero-length-bounds')
+conf.set10('HAVE_ZERO_LENGTH_BOUNDS', have)
+
if cc.compiles('''
#include <time.h>
#include <inttypes.h>
############################################################
-conf.set_quoted('FALLBACK_HOSTNAME', get_option('fallback-hostname'))
+fallback_hostname = get_option('fallback-hostname')
+if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0] == '-'
+ error('Invalid fallback-hostname configuration')
+ # A more extensive test is done in test-hostname-util. Let's catch
+ # the most obvious errors here so we don't fail with an assert later.
+endif
+conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname)
+
conf.set10('ENABLE_COMPAT_GATEWAY_HOSTNAME', get_option('compat-gateway-hostname'))
gateway_hostnames = ['_gateway'] + (conf.get('ENABLE_COMPAT_GATEWAY_HOSTNAME') == 1 ? ['gateway'] : [])
time_epoch = get_option('time-epoch')
if time_epoch == -1
- NEWS = files('NEWS')
- time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
+ source_date_epoch = run_command('sh', ['-c', 'echo "$SOURCE_DATE_EPOCH"']).stdout().strip()
+ if source_date_epoch != ''
+ time_epoch = source_date_epoch.to_int()
+ else
+ NEWS = files('NEWS')
+ time_epoch = run_command(stat, '-c', '%Y', NEWS).stdout().to_int()
+ endif
endif
conf.set('TIME_EPOCH', time_epoch)
want_p11kit = get_option('p11kit')
if want_p11kit != 'false' and not skip_deps
libp11kit = dependency('p11-kit-1',
- version : '>= 0.23.3',
- required : want_p11kit == 'true')
+ version : '>= 0.23.3',
+ required : want_p11kit == 'true')
have = libp11kit.found()
else
have = false
endif
conf.set10('HAVE_LZ4', have)
+want_zstd = get_option('zstd')
+if want_zstd != 'false' and not skip_deps
+ libzstd = dependency('libzstd',
+ required : want_zstd == 'true',
+ version : '>= 1.4.0')
+ have = libzstd.found()
+else
+ have = false
+ libzstd = []
+endif
+conf.set10('HAVE_ZSTD', have)
+
want_xkbcommon = get_option('xkbcommon')
if want_xkbcommon != 'false' and not skip_deps
libxkbcommon = dependency('xkbcommon',
'smack',
'gshadow',
'idn',
+ 'initrd',
'nss-myhostname',
'nss-systemd']
have = get_option(term)
includes = include_directories('src/basic',
'src/boot',
+ 'src/home',
'src/shared',
'src/systemd',
'src/journal',
dependencies : [threads,
librt,
libxz,
+ libzstd,
liblz4],
link_depends : libsystemd_sym,
install : true,
dependencies : [threads,
librt,
libxz,
+ libzstd,
liblz4,
libcap,
libblkid,
libgcrypt],
c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC']))
-#Generate autosuspend rules
+# Generate autosuspend rules
make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py')
############################################################
############################################################
-executable('systemd',
- systemd_sources,
- include_directories : includes,
- link_with : [libcore,
- libshared],
- dependencies : [versiondep,
- threads,
- librt,
- libseccomp,
- libselinux,
- libmount,
- libblkid],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+executable(
+ 'systemd',
+ systemd_sources,
+ include_directories : includes,
+ link_with : [libcore,
+ libshared],
+ dependencies : [versiondep,
+ threads,
+ librt,
+ libseccomp,
+ libselinux,
+ libmount,
+ libblkid],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
meson.add_install_script(meson_make_symlink,
join_paths(rootlibexecdir, 'systemd'),
join_paths(rootsbindir, 'init'))
-exe = executable('systemd-analyze',
- systemd_analyze_sources,
- include_directories : includes,
- link_with : [libcore,
- libshared],
- dependencies : [versiondep,
- threads,
- librt,
- libseccomp,
- libselinux,
- libmount,
- libblkid],
- install_rpath : rootlibexecdir,
- install : get_option('analyze'))
-public_programs += exe
-
-executable('systemd-journald',
- systemd_journald_sources,
- include_directories : includes,
- link_with : [libjournal_core,
- libshared],
- dependencies : [threads,
- libxz,
- liblz4,
- libselinux],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-analyze',
+ systemd_analyze_sources,
+ include_directories : includes,
+ link_with : [libcore,
+ libshared],
+ dependencies : [versiondep,
+ threads,
+ librt,
+ libseccomp,
+ libselinux,
+ libmount,
+ libblkid],
+ install_rpath : rootlibexecdir,
+ install : get_option('analyze'))
-exe = executable('systemd-cat',
- systemd_cat_sources,
- include_directories : includes,
- link_with : [libjournal_core,
- libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('journalctl',
- journalctl_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libqrencode,
- libxz,
- liblz4,
- libpcre2],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-getty-generator',
- 'src/getty-generator/getty-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+executable(
+ 'systemd-journald',
+ systemd_journald_sources,
+ include_directories : includes,
+ link_with : [libjournal_core,
+ libshared],
+ dependencies : [threads,
+ libxz,
+ liblz4,
+ libselinux,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
-executable('systemd-debug-generator',
- 'src/debug-generator/debug-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+public_programs += executable(
+ 'systemd-cat',
+ systemd_cat_sources,
+ include_directories : includes,
+ link_with : [libjournal_core,
+ libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+public_programs += executable(
+ 'journalctl',
+ journalctl_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libqrencode,
+ libxz,
+ liblz4,
+ libpcre2,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
-executable('systemd-run-generator',
- 'src/run-generator/run-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+executable(
+ 'systemd-getty-generator',
+ 'src/getty-generator/getty-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
-executable('systemd-fstab-generator',
- 'src/fstab-generator/fstab-generator.c',
- include_directories : includes,
- link_with : [libcore_shared,
- libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+executable(
+ 'systemd-debug-generator',
+ 'src/debug-generator/debug-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+
+executable(
+ 'systemd-run-generator',
+ 'src/run-generator/run-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+
+executable(
+ 'systemd-fstab-generator',
+ 'src/fstab-generator/fstab-generator.c',
+ include_directories : includes,
+ link_with : [libcore_shared,
+ libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
if conf.get('ENABLE_ENVIRONMENT_D') == 1
- executable('30-systemd-environment-d-generator',
- 'src/environment-d-generator/environment-d-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : userenvgeneratordir)
+ executable(
+ '30-systemd-environment-d-generator',
+ 'src/environment-d-generator/environment-d-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : userenvgeneratordir)
meson.add_install_script(meson_make_symlink,
join_paths(sysconfdir, 'environment'),
endif
if conf.get('ENABLE_HIBERNATE') == 1
- executable('systemd-hibernate-resume-generator',
- 'src/hibernate-resume/hibernate-resume-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
-
- executable('systemd-hibernate-resume',
- 'src/hibernate-resume/hibernate-resume.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-hibernate-resume-generator',
+ 'src/hibernate-resume/hibernate-resume-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+
+ executable(
+ 'systemd-hibernate-resume',
+ 'src/hibernate-resume/hibernate-resume.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('HAVE_BLKID') == 1
- executable('systemd-gpt-auto-generator',
- 'src/gpt-auto-generator/gpt-auto-generator.c',
- 'src/shared/blkid-util.h',
- include_directories : includes,
- link_with : [libshared],
- dependencies : libblkid,
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
-
- exe = executable('systemd-dissect',
- 'src/dissect/dissect.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
- public_programs += exe
+ executable(
+ 'systemd-gpt-auto-generator',
+ 'src/gpt-auto-generator/gpt-auto-generator.c',
+ 'src/shared/blkid-util.h',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : libblkid,
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+
+ public_programs += executable(
+ 'systemd-dissect',
+ 'src/dissect/dissect.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_RESOLVE') == 1
- executable('systemd-resolved',
- systemd_resolved_sources,
- include_directories : includes,
- link_with : [libshared,
- libbasic_gcrypt,
- libsystemd_resolve_core],
- dependencies : systemd_resolved_dependencies,
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('resolvectl',
- resolvectl_sources,
- include_directories : includes,
- link_with : [libshared,
- libbasic_gcrypt,
- libsystemd_resolve_core],
- dependencies : [threads,
- libgpg_error,
- libm,
- libidn],
- install_rpath : rootlibexecdir,
- install : true)
- public_programs += exe
+ executable(
+ 'systemd-resolved',
+ systemd_resolved_sources,
+ include_directories : includes,
+ link_with : [libshared,
+ libbasic_gcrypt,
+ libsystemd_resolve_core],
+ dependencies : systemd_resolved_dependencies,
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'resolvectl',
+ resolvectl_sources,
+ include_directories : includes,
+ link_with : [libshared,
+ libbasic_gcrypt,
+ libsystemd_resolve_core],
+ dependencies : [threads,
+ libgpg_error,
+ libm,
+ libidn],
+ install_rpath : rootlibexecdir,
+ install : true)
meson.add_install_script(meson_make_symlink,
- join_paths(bindir, 'resolvectl'),
- join_paths(rootsbindir, 'resolvconf'))
+ join_paths(bindir, 'resolvectl'),
+ join_paths(rootsbindir, 'resolvconf'))
meson.add_install_script(meson_make_symlink,
- join_paths(bindir, 'resolvectl'),
- join_paths(bindir, 'systemd-resolve'))
+ join_paths(bindir, 'resolvectl'),
+ join_paths(bindir, 'systemd-resolve'))
endif
if conf.get('ENABLE_LOGIND') == 1
- executable('systemd-logind',
- systemd_logind_sources,
- include_directories : includes,
- link_with : [liblogind_core,
- libshared],
- dependencies : [threads,
- libacl],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('loginctl',
- loginctl_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- liblz4,
- libxz],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
-
- exe = executable('systemd-inhibit',
- 'src/login/inhibit.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
+ executable(
+ 'systemd-logind',
+ systemd_logind_sources,
+ include_directories : includes,
+ link_with : [liblogind_core,
+ libshared],
+ dependencies : [threads,
+ libacl],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'loginctl',
+ loginctl_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ liblz4,
+ libxz,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+
+ public_programs += executable(
+ 'systemd-inhibit',
+ 'src/login/inhibit.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
if conf.get('HAVE_PAM') == 1
version_script_arg = join_paths(project_source_root, pam_systemd_sym)
endif
endif
- executable('systemd-user-runtime-dir',
- user_runtime_dir_sources,
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-user-runtime-dir',
+ user_runtime_dir_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('HAVE_PAM') == 1
- executable('systemd-user-sessions',
- 'src/user-sessions/user-sessions.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-user-sessions',
+ 'src/user-sessions/user-sessions.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_EFI') == 1 and conf.get('HAVE_BLKID') == 1
- exe = executable('bootctl',
- 'src/boot/bootctl.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libblkid],
- install_rpath : rootlibexecdir,
- install : true)
- public_programs += exe
-
- executable('systemd-bless-boot',
- 'src/boot/bless-boot.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libblkid],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-bless-boot-generator',
- 'src/boot/bless-boot-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
-endif
-
-executable('systemd-boot-check-no-failures',
- 'src/boot/boot-check-no-failures.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libblkid],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
-exe = executable('systemd-socket-activate', 'src/activate/activate.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
+ public_programs += executable(
+ 'bootctl',
+ 'src/boot/bootctl.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libblkid],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+ public_programs += executable(
+ 'systemd-bless-boot',
+ 'src/boot/bless-boot.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libblkid],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-bless-boot-generator',
+ 'src/boot/bless-boot-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+endif
+
+executable(
+ 'systemd-boot-check-no-failures',
+ 'src/boot/boot-check-no-failures.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libblkid],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-socket-activate',
+ 'src/activate/activate.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true)
if get_option('link-systemctl-shared')
systemctl_link_with = [libshared]
libbasic_gcrypt]
endif
-exe = executable('systemctl',
- 'src/systemctl/systemctl.c',
- 'src/systemctl/sysv-compat.h',
- 'src/systemctl/sysv-compat.c',
- include_directories : includes,
- link_with : systemctl_link_with,
- dependencies : [threads,
- libcap,
- libselinux,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
+public_programs += executable(
+ 'systemctl',
+ 'src/systemctl/systemctl.c',
+ 'src/systemctl/sysv-compat.h',
+ 'src/systemctl/sysv-compat.c',
+ include_directories : includes,
+ link_with : systemctl_link_with,
+ dependencies : [threads,
+ libcap,
+ libselinux,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
if conf.get('ENABLE_PORTABLED') == 1
- executable('systemd-portabled',
- systemd_portabled_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('portablectl', 'src/portable/portablectl.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
+ executable(
+ 'systemd-portabled',
+ systemd_portabled_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'portablectl',
+ 'src/portable/portablectl.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
endif
if conf.get('ENABLE_USERDB') == 1
- executable('systemd-userwork',
- systemd_userwork_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-userdbd',
- systemd_userdbd_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('userdbctl',
- userdbctl_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
+ executable(
+ 'systemd-userwork',
+ systemd_userwork_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-userdbd',
+ systemd_userdbd_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'userdbctl',
+ userdbctl_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
endif
if conf.get('ENABLE_HOMED') == 1
- executable('systemd-homework',
- systemd_homework_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libcryptsetup,
- libblkid,
- libcrypt,
- libopenssl,
- libfdisk,
- libp11kit],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-homed',
- systemd_homed_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libcrypt,
- libopenssl,
- libpwquality],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('homectl',
- homectl_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libcrypt,
- libopenssl,
- libp11kit,
- libpwquality],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
+ executable(
+ 'systemd-homework',
+ systemd_homework_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libcryptsetup,
+ libblkid,
+ libcrypt,
+ libopenssl,
+ libfdisk,
+ libp11kit],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-homed',
+ systemd_homed_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libcrypt,
+ libopenssl,
+ libpwquality],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'homectl',
+ homectl_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libcrypt,
+ libopenssl,
+ libp11kit,
+ libpwquality],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
if conf.get('HAVE_PAM') == 1
version_script_arg = join_paths(project_source_root, pam_systemd_home_sym)
endforeach
if conf.get('ENABLE_BACKLIGHT') == 1
- executable('systemd-backlight',
- 'src/backlight/backlight.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-backlight',
+ 'src/backlight/backlight.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_RFKILL') == 1
- executable('systemd-rfkill',
- 'src/rfkill/rfkill.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-endif
-
-executable('systemd-system-update-generator',
- 'src/system-update-generator/system-update-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+ executable(
+ 'systemd-rfkill',
+ 'src/rfkill/rfkill.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+endif
+
+executable(
+ 'systemd-system-update-generator',
+ 'src/system-update-generator/system-update-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
if conf.get('HAVE_LIBCRYPTSETUP') == 1
systemd_cryptsetup_sources = files('''
- src/cryptsetup/cryptsetup.c
src/cryptsetup/cryptsetup-pkcs11.h
+ src/cryptsetup/cryptsetup-util.c
+ src/cryptsetup/cryptsetup-util.h
+ src/cryptsetup/cryptsetup.c
'''.split())
if conf.get('HAVE_P11KIT') == 1
systemd_cryptsetup_sources += files('src/cryptsetup/cryptsetup-pkcs11.c')
endif
- executable('systemd-cryptsetup',
- systemd_cryptsetup_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcryptsetup,
- libp11kit],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-cryptsetup-generator',
- 'src/cryptsetup/cryptsetup-generator.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcryptsetup],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
-
- executable('systemd-veritysetup',
- 'src/veritysetup/veritysetup.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcryptsetup],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-veritysetup-generator',
- 'src/veritysetup/veritysetup-generator.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcryptsetup],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+ executable(
+ 'systemd-cryptsetup',
+ systemd_cryptsetup_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcryptsetup,
+ libp11kit],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-cryptsetup-generator',
+ 'src/cryptsetup/cryptsetup-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcryptsetup],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+
+ executable(
+ 'systemd-veritysetup',
+ 'src/veritysetup/veritysetup.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcryptsetup],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-veritysetup-generator',
+ 'src/veritysetup/veritysetup-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcryptsetup],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
endif
if conf.get('HAVE_SYSV_COMPAT') == 1
- executable('systemd-sysv-generator',
- 'src/sysv-generator/sysv-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
-
- executable('systemd-rc-local-generator',
- 'src/rc-local-generator/rc-local-generator.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : systemgeneratordir)
+ executable(
+ 'systemd-sysv-generator',
+ 'src/sysv-generator/sysv-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
+
+ executable(
+ 'systemd-rc-local-generator',
+ 'src/rc-local-generator/rc-local-generator.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : systemgeneratordir)
endif
if conf.get('ENABLE_HOSTNAMED') == 1
- executable('systemd-hostnamed',
- 'src/hostname/hostnamed.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('hostnamectl',
- 'src/hostname/hostnamectl.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
- public_programs += exe
+ executable(
+ 'systemd-hostnamed',
+ 'src/hostname/hostnamed.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'hostnamectl',
+ 'src/hostname/hostnamectl.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
endif
if conf.get('ENABLE_LOCALED') == 1
deps = []
endif
- executable('systemd-localed',
- systemd_localed_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : deps,
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('localectl',
- localectl_sources,
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
- public_programs += exe
+ executable(
+ 'systemd-localed',
+ systemd_localed_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : deps,
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'localectl',
+ localectl_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
endif
if conf.get('ENABLE_TIMEDATED') == 1
- executable('systemd-timedated',
- 'src/timedate/timedated.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-timedated',
+ 'src/timedate/timedated.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_TIMEDATECTL') == 1
- exe = executable('timedatectl',
- 'src/timedate/timedatectl.c',
- include_directories : includes,
- install_rpath : rootlibexecdir,
- link_with : [libshared],
- dependencies : [libm],
- install : true)
- public_programs += exe
+ public_programs += executable(
+ 'timedatectl',
+ 'src/timedate/timedatectl.c',
+ include_directories : includes,
+ install_rpath : rootlibexecdir,
+ link_with : [libshared],
+ dependencies : [libm],
+ install : true)
endif
if conf.get('ENABLE_TIMESYNCD') == 1
libbasic_gcrypt]
endif
- executable('systemd-timesyncd',
- systemd_timesyncd_sources,
- include_directories : includes,
- link_with : [timesyncd_link_with],
- dependencies : [threads,
- libm],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-time-wait-sync',
- 'src/time-wait-sync/time-wait-sync.c',
- include_directories : includes,
- link_with : [timesyncd_link_with],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-timesyncd',
+ systemd_timesyncd_sources,
+ include_directories : includes,
+ link_with : [timesyncd_link_with],
+ dependencies : [threads,
+ libm],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-time-wait-sync',
+ 'src/time-wait-sync/time-wait-sync.c',
+ include_directories : includes,
+ link_with : [timesyncd_link_with],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_MACHINED') == 1
- executable('systemd-machined',
- systemd_machined_sources,
- include_directories : includes,
- link_with : [libmachine_core,
- libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('machinectl',
- 'src/machine/machinectl.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
+ executable(
+ 'systemd-machined',
+ systemd_machined_sources,
+ include_directories : includes,
+ link_with : [libmachine_core,
+ libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'machinectl',
+ 'src/machine/machinectl.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
endif
if conf.get('ENABLE_IMPORTD') == 1
- executable('systemd-importd',
- systemd_importd_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- systemd_pull = executable('systemd-pull',
- systemd_pull_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [versiondep,
- libcurl,
- libz,
- libbzip2,
- libxz,
- libgcrypt],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- systemd_import = executable('systemd-import',
- systemd_import_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcurl,
- libz,
- libbzip2,
- libxz],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- systemd_import_fs = executable('systemd-import-fs',
- systemd_import_fs_sources,
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- systemd_export = executable('systemd-export',
- systemd_export_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcurl,
- libz,
- libbzip2,
- libxz],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-importd',
+ systemd_importd_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ systemd_pull = executable(
+ 'systemd-pull',
+ systemd_pull_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [versiondep,
+ libcurl,
+ libz,
+ libbzip2,
+ libxz,
+ libgcrypt],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ systemd_import = executable(
+ 'systemd-import',
+ systemd_import_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcurl,
+ libz,
+ libbzip2,
+ libxz],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ systemd_import_fs = executable(
+ 'systemd-import-fs',
+ systemd_import_fs_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ systemd_export = executable(
+ 'systemd-export',
+ systemd_export_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcurl,
+ libz,
+ libbzip2,
+ libxz],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
public_programs += [systemd_pull, systemd_import, systemd_import_fs, systemd_export]
endif
if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_LIBCURL') == 1
- exe = executable('systemd-journal-upload',
- systemd_journal_upload_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [versiondep,
- threads,
- libcurl,
- libgnutls,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
- public_programs += exe
+ public_programs += executable(
+ 'systemd-journal-upload',
+ systemd_journal_upload_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [versiondep,
+ threads,
+ libcurl,
+ libgnutls,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
- s_j_remote = executable('systemd-journal-remote',
- systemd_journal_remote_sources,
- include_directories : includes,
- link_with : [libshared,
- libsystemd_journal_remote],
- dependencies : [threads,
- libmicrohttpd,
- libgnutls,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- s_j_gatewayd = executable('systemd-journal-gatewayd',
- systemd_journal_gatewayd_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libmicrohttpd,
- libgnutls,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
- public_programs += [s_j_remote, s_j_gatewayd]
+ public_programs += executable(
+ 'systemd-journal-remote',
+ systemd_journal_remote_sources,
+ include_directories : includes,
+ link_with : [libshared,
+ libsystemd_journal_remote],
+ dependencies : [threads,
+ libmicrohttpd,
+ libgnutls,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'systemd-journal-gatewayd',
+ systemd_journal_gatewayd_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libmicrohttpd,
+ libgnutls,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_COREDUMP') == 1
- executable('systemd-coredump',
- systemd_coredump_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libacl,
- libdw,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('coredumpctl',
- coredumpctl_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true)
- public_programs += exe
+ executable(
+ 'systemd-coredump',
+ systemd_coredump_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libacl,
+ libdw,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'coredumpctl',
+ coredumpctl_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true)
endif
if conf.get('ENABLE_PSTORE') == 1
- executable('systemd-pstore',
- systemd_pstore_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libacl,
- libdw,
- libxz,
- liblz4],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-pstore',
+ systemd_pstore_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libacl,
+ libdw,
+ libxz,
+ liblz4,
+ libzstd],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_BINFMT') == 1
- exe = executable('systemd-binfmt',
- 'src/binfmt/binfmt.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
- public_programs += exe
+ public_programs += executable(
+ 'systemd-binfmt',
+ 'src/binfmt/binfmt.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
meson.add_install_script('sh', '-c',
mkdir_p.format(binfmtdir))
endif
if conf.get('ENABLE_REPART') == 1
- exe = executable('systemd-repart',
- systemd_repart_sources,
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads,
- libcryptsetup,
- libblkid,
- libfdisk,
- libopenssl],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
+ exe = executable(
+ 'systemd-repart',
+ systemd_repart_sources,
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads,
+ libcryptsetup,
+ libblkid,
+ libfdisk,
+ libopenssl],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
if want_tests != 'false'
test('test-repart',
endif
if conf.get('ENABLE_VCONSOLE') == 1
- executable('systemd-vconsole-setup',
- 'src/vconsole/vconsole-setup.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-vconsole-setup',
+ 'src/vconsole/vconsole-setup.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_RANDOMSEED') == 1
- executable('systemd-random-seed',
- 'src/random-seed/random-seed.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-random-seed',
+ 'src/random-seed/random-seed.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_FIRSTBOOT') == 1
- executable('systemd-firstboot',
- 'src/firstboot/firstboot.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libcrypt],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-endif
-
-executable('systemd-remount-fs',
- 'src/remount-fs/remount-fs.c',
- include_directories : includes,
- link_with : [libcore_shared,
- libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-firstboot',
+ 'src/firstboot/firstboot.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libcrypt],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+endif
+
+executable(
+ 'systemd-remount-fs',
+ 'src/remount-fs/remount-fs.c',
+ include_directories : includes,
+ link_with : [libcore_shared,
+ libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
-executable('systemd-machine-id-setup',
- 'src/machine-id-setup/machine-id-setup-main.c',
- include_directories : includes,
- link_with : [libcore_shared,
- libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
+executable(
+ 'systemd-machine-id-setup',
+ 'src/machine-id-setup/machine-id-setup-main.c',
+ include_directories : includes,
+ link_with : [libcore_shared,
+ libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
-executable('systemd-fsck',
- 'src/fsck/fsck.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+executable(
+ 'systemd-fsck',
+ 'src/fsck/fsck.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
executable('systemd-growfs',
'src/partition/growfs.c',
install : true,
install_dir : rootlibexecdir)
-executable('systemd-makefs',
- 'src/partition/makefs.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+executable(
+ 'systemd-makefs',
+ 'src/partition/makefs.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
-executable('systemd-sleep',
- 'src/sleep/sleep.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+executable(
+ 'systemd-sleep',
+ 'src/sleep/sleep.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
install_data('src/sleep/sleep.conf',
install_dir : pkgsysconfdir)
-exe = executable('systemd-sysctl',
- 'src/sysctl/sysctl.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-public_programs += exe
-
-executable('systemd-ac-power',
- 'src/ac-power/ac-power.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-sysctl',
+ 'src/sysctl/sysctl.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
-exe = executable('systemd-detect-virt',
- 'src/detect-virt/detect-virt.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('systemd-delta',
- 'src/delta/delta.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('systemd-escape',
- 'src/escape/escape.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
-
-exe = executable('systemd-notify',
- 'src/notify/notify.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-volatile-root',
- 'src/volatile-root/volatile-root.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+executable(
+ 'systemd-ac-power',
+ 'src/ac-power/ac-power.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
-executable('systemd-cgroups-agent',
- 'src/cgroups-agent/cgroups-agent.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-detect-virt',
+ 'src/detect-virt/detect-virt.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
-exe = executable('systemd-id128',
- 'src/id128/id128.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('systemd-path',
- 'src/path/path.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('systemd-ask-password',
- 'src/ask-password/ask-password.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-reply-password',
- 'src/reply-password/reply-password.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-delta',
+ 'src/delta/delta.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
-exe = executable('systemd-tty-ask-password-agent',
- 'src/tty-ask-password-agent/tty-ask-password-agent.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
-
-exe = executable('systemd-cgls',
- 'src/cgls/cgls.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('systemd-cgtop',
- 'src/cgtop/cgtop.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-executable('systemd-initctl',
- 'src/initctl/initctl.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-escape',
+ 'src/escape/escape.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+
+public_programs += executable(
+ 'systemd-notify',
+ 'src/notify/notify.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+
+executable(
+ 'systemd-volatile-root',
+ 'src/volatile-root/volatile-root.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : conf.get('ENABLE_INITRD') == 1,
+ install_dir : rootlibexecdir)
+
+executable(
+ 'systemd-cgroups-agent',
+ 'src/cgroups-agent/cgroups-agent.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+public_programs += executable(
+ 'systemd-id128',
+ 'src/id128/id128.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+public_programs += executable(
+ 'systemd-path',
+ 'src/path/path.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+public_programs += executable(
+ 'systemd-ask-password',
+ 'src/ask-password/ask-password.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+
+executable(
+ 'systemd-reply-password',
+ 'src/reply-password/reply-password.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+public_programs += executable(
+ 'systemd-tty-ask-password-agent',
+ 'src/tty-ask-password-agent/tty-ask-password-agent.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+
+public_programs += executable(
+ 'systemd-cgls',
+ 'src/cgls/cgls.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+public_programs += executable(
+ 'systemd-cgtop',
+ 'src/cgtop/cgtop.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
-exe = executable('systemd-mount',
- 'src/mount/mount-tool.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies: [libmount],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
+executable(
+ 'systemd-initctl',
+ 'src/initctl/initctl.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+public_programs += executable(
+ 'systemd-mount',
+ 'src/mount/mount-tool.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies: [libmount],
+ install_rpath : rootlibexecdir,
+ install : true)
meson.add_install_script(meson_make_symlink,
'systemd-mount', join_paths(bindir, 'systemd-umount'))
-exe = executable('systemd-run',
- 'src/run/run.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('systemd-stdio-bridge',
- 'src/stdio-bridge/stdio-bridge.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [versiondep],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
-
-exe = executable('busctl',
- 'src/busctl/busctl.c',
- 'src/busctl/busctl-introspect.c',
- 'src/busctl/busctl-introspect.h',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
+public_programs += executable(
+ 'systemd-run',
+ 'src/run/run.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+public_programs += executable(
+ 'systemd-stdio-bridge',
+ 'src/stdio-bridge/stdio-bridge.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [versiondep],
+ install_rpath : rootlibexecdir,
+ install : true)
+
+public_programs += executable(
+ 'busctl',
+ 'src/busctl/busctl.c',
+ 'src/busctl/busctl-introspect.c',
+ 'src/busctl/busctl-introspect.h',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true)
if conf.get('ENABLE_SYSUSERS') == 1
- exe = executable('systemd-sysusers',
- 'src/sysusers/sysusers.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
+ public_programs += executable(
+ 'systemd-sysusers',
+ 'src/sysusers/sysusers.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
endif
if conf.get('ENABLE_TMPFILES') == 1
- exe = executable('systemd-tmpfiles',
- 'src/tmpfiles/tmpfiles.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libacl],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
+ exe = executable(
+ 'systemd-tmpfiles',
+ 'src/tmpfiles/tmpfiles.c',
+ 'src/tmpfiles/offline-passwd.c',
+ 'src/tmpfiles/offline-passwd.h',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libacl],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
public_programs += exe
if want_tests != 'false'
endif
if conf.get('ENABLE_HWDB') == 1
- exe = executable('systemd-hwdb',
- 'src/hwdb/hwdb.c',
- 'src/libsystemd/sd-hwdb/hwdb-internal.h',
- include_directories : includes,
- link_with : [libudev_static],
- install_rpath : udev_rpath,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
+ public_programs += executable(
+ 'systemd-hwdb',
+ 'src/hwdb/hwdb.c',
+ 'src/libsystemd/sd-hwdb/hwdb-internal.h',
+ include_directories : includes,
+ link_with : [libudev_static],
+ install_rpath : udev_rpath,
+ install : true,
+ install_dir : rootbindir)
endif
if conf.get('ENABLE_QUOTACHECK') == 1
- executable('systemd-quotacheck',
- 'src/quotacheck/quotacheck.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-endif
-
-exe = executable('systemd-socket-proxyd',
- 'src/socket-proxy/socket-proxyd.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-public_programs += exe
-
-exe = executable('systemd-udevd',
- systemd_udevd_sources,
- include_directories : includes,
- c_args : '-DLOG_REALM=LOG_REALM_UDEV',
- link_with : [libudev_core,
- libsystemd_network,
- libudev_static],
- dependencies : [versiondep,
- threads,
- libkmod,
- libidn,
- libacl,
- libblkid],
- install_rpath : udev_rpath,
- install : true,
- install_dir : rootlibexecdir)
-public_programs += exe
-
-exe = executable('udevadm',
- udevadm_sources,
- c_args : '-DLOG_REALM=LOG_REALM_UDEV',
- include_directories : includes,
- link_with : [libudev_core,
- libsystemd_network,
- libudev_static],
- dependencies : [versiondep,
- threads,
- libkmod,
- libidn,
- libacl,
- libblkid],
- install_rpath : udev_rpath,
- install : true,
- install_dir : rootbindir)
-public_programs += exe
-
-executable('systemd-shutdown',
- systemd_shutdown_sources,
- include_directories : includes,
- link_with : [libcore_shared,
- libshared],
- dependencies : [libmount],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-quotacheck',
+ 'src/quotacheck/quotacheck.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+endif
+
+public_programs += executable(
+ 'systemd-socket-proxyd',
+ 'src/socket-proxy/socket-proxyd.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
-executable('systemd-update-done',
- 'src/update-done/update-done.c',
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'systemd-udevd',
+ systemd_udevd_sources,
+ include_directories : includes,
+ c_args : '-DLOG_REALM=LOG_REALM_UDEV',
+ link_with : [libudev_core,
+ libsystemd_network,
+ libudev_static],
+ dependencies : [versiondep,
+ threads,
+ libkmod,
+ libidn,
+ libacl,
+ libblkid],
+ install_rpath : udev_rpath,
+ install : true,
+ install_dir : rootlibexecdir)
-executable('systemd-update-utmp',
- 'src/update-utmp/update-utmp.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libaudit],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+public_programs += executable(
+ 'udevadm',
+ udevadm_sources,
+ c_args : '-DLOG_REALM=LOG_REALM_UDEV',
+ include_directories : includes,
+ link_with : [libudev_core,
+ libsystemd_network,
+ libudev_static],
+ dependencies : [versiondep,
+ threads,
+ libkmod,
+ libidn,
+ libacl,
+ libblkid],
+ install_rpath : udev_rpath,
+ install : true,
+ install_dir : rootbindir)
+
+executable(
+ 'systemd-shutdown',
+ systemd_shutdown_sources,
+ include_directories : includes,
+ link_with : [libcore_shared,
+ libshared],
+ dependencies : [libmount],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+executable(
+ 'systemd-update-done',
+ 'src/update-done/update-done.c',
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+executable(
+ 'systemd-update-utmp',
+ 'src/update-utmp/update-utmp.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libaudit],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
if conf.get('HAVE_KMOD') == 1
- executable('systemd-modules-load',
- 'src/modules-load/modules-load.c',
- include_directories : includes,
- link_with : [libshared],
- dependencies : [libkmod],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-modules-load',
+ 'src/modules-load/modules-load.c',
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [libkmod],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
meson.add_install_script('sh', '-c',
mkdir_p.format(modulesloaddir))
mkdir_p.format(join_paths(sysconfdir, 'modules-load.d')))
endif
-exe = executable('systemd-nspawn',
- systemd_nspawn_sources,
- include_directories : includes,
- link_with : [libcore_shared,
- libnspawn_core,
- libshared],
- dependencies : [libblkid,
- libseccomp],
- install_rpath : rootlibexecdir,
- install : true)
-public_programs += exe
+public_programs += executable(
+ 'systemd-nspawn',
+ systemd_nspawn_sources,
+ include_directories : includes,
+ link_with : [libcore_shared,
+ libnspawn_core,
+ libshared],
+ dependencies : [libblkid,
+ libseccomp],
+ install_rpath : rootlibexecdir,
+ install : true)
if conf.get('ENABLE_NETWORKD') == 1
- executable('systemd-networkd',
- systemd_networkd_sources,
- include_directories : network_include_dir,
- link_with : [libnetworkd_core,
- libsystemd_network,
- libudev_static,
- networkd_link_with],
- dependencies : [threads],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- executable('systemd-networkd-wait-online',
- systemd_networkd_wait_online_sources,
- include_directories : includes,
- link_with : [libnetworkd_core,
- networkd_link_with],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
-
- exe = executable('networkctl',
- networkctl_sources,
- include_directories : includes,
- link_with : [libsystemd_network,
- networkd_link_with],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootbindir)
- public_programs += exe
-
- exe = executable('systemd-network-generator',
- network_generator_sources,
- include_directories : includes,
- link_with : [networkd_link_with],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+ executable(
+ 'systemd-networkd',
+ systemd_networkd_sources,
+ include_directories : network_include_dir,
+ link_with : [libnetworkd_core,
+ libsystemd_network,
+ libudev_static,
+ networkd_link_with],
+ dependencies : [threads],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ executable(
+ 'systemd-networkd-wait-online',
+ systemd_networkd_wait_online_sources,
+ include_directories : includes,
+ link_with : [libnetworkd_core,
+ networkd_link_with],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
+
+ public_programs += executable(
+ 'networkctl',
+ networkctl_sources,
+ include_directories : includes,
+ link_with : [libsystemd_network,
+ networkd_link_with],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootbindir)
+
+ exe = executable(
+ 'systemd-network-generator',
+ network_generator_sources,
+ include_directories : includes,
+ link_with : [networkd_link_with],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
if want_tests != 'false'
test('test-network-generator-conversion',
endif
endif
-executable('systemd-sulogin-shell',
- ['src/sulogin-shell/sulogin-shell.c'],
- include_directories : includes,
- link_with : [libshared],
- install_rpath : rootlibexecdir,
- install : true,
- install_dir : rootlibexecdir)
+executable(
+ 'systemd-sulogin-shell',
+ ['src/sulogin-shell/sulogin-shell.c'],
+ include_directories : includes,
+ link_with : [libshared],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
############################################################
output : 'systemd-runtest.env',
command : ['sh', '-c', '{ ' +
'echo SYSTEMD_TEST_DATA=@0@; '.format(join_paths(project_source_root, 'test')) +
- 'echo SYSTEMD_CATALOG_DIR=@0@; '.format(join_paths(meson.current_build_dir(), 'catalog')) +
+ 'echo SYSTEMD_CATALOG_DIR=@0@; '.format(join_paths(project_build_root, 'catalog')) +
'} >@OUTPUT@'],
build_by_default : true)
fuzzer_exes = []
if get_option('tests') != 'false'
-foreach tuple : fuzzers
- sources = tuple[0]
- link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
- dependencies = tuple[2]
- defs = tuple.length() >= 4 ? tuple[3] : []
- incs = tuple.length() >= 5 ? tuple[4] : includes
- link_args = []
-
- if want_ossfuzz
- dependencies += fuzzing_engine
- elif want_libfuzzer
- if fuzzing_engine.found()
+ foreach tuple : fuzzers
+ sources = tuple[0]
+ link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
+ dependencies = tuple[2]
+ defs = tuple.length() >= 4 ? tuple[3] : []
+ incs = tuple.length() >= 5 ? tuple[4] : includes
+ link_args = []
+
+ if want_ossfuzz
dependencies += fuzzing_engine
+ elif want_libfuzzer
+ if fuzzing_engine.found()
+ dependencies += fuzzing_engine
+ else
+ link_args += ['-fsanitize=fuzzer']
+ endif
else
- link_args += ['-fsanitize=fuzzer']
+ sources += 'src/fuzz/fuzz-main.c'
endif
- else
- sources += 'src/fuzz/fuzz-main.c'
- endif
- name = sources[0].split('/')[-1].split('.')[0]
+ name = sources[0].split('/')[-1].split('.')[0]
- fuzzer_exes += executable(
- name,
- sources,
- include_directories : [incs, include_directories('src/fuzz')],
- link_with : link_with,
- dependencies : dependencies,
- c_args : defs,
- link_args: link_args,
- install : false)
-endforeach
+ fuzzer_exes += executable(
+ name,
+ sources,
+ include_directories : [incs, include_directories('src/fuzz')],
+ link_with : link_with,
+ dependencies : dependencies,
+ c_args : defs,
+ link_args: link_args,
+ install : false)
+ endforeach
endif
-run_target('fuzzers',
+run_target(
+ 'fuzzers',
depends : fuzzer_exes,
command : ['true'])
make_directive_index_py = find_program('tools/make-directive-index.py')
make_man_index_py = find_program('tools/make-man-index.py')
xml_helper_py = find_program('tools/xml_helper.py')
-hwdb_update_sh = find_program('tools/meson-hwdb-update.sh')
-autosuspend_update_sh = find_program('tools/meson-autosuspend-update.sh')
+hwdb_update_sh = find_program('tools/hwdb-update.sh')
+autosuspend_update_sh = find_program('tools/autosuspend-update.sh')
subdir('sysctl.d')
subdir('sysusers.d')
############################################################
-meson_check_help = find_program('tools/meson-check-help.sh')
+check_help = find_program('tools/check-help.sh')
foreach exec : public_programs
name = exec.full_path().split('/')[-1]
if want_tests != 'false'
test('check-help-' + name,
- meson_check_help,
+ check_help,
args : exec.full_path())
endif
endforeach
if want_tests != 'false' and slow_tests
test('@0@:@1@:@2@'.format(b, c, sanitizer),
env,
+ env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
+ timeout : 60,
args : [exe.full_path(),
join_paths(project_source_root, p)])
endif
endif
if git.found()
- meson_git_contrib_sh = find_program('tools/meson-git-contrib.sh')
+ git_contrib_sh = find_program('tools/git-contrib.sh')
run_target(
'git-contrib',
- command : [meson_git_contrib_sh])
+ command : [git_contrib_sh])
endif
if git.found()
############################################################
-meson_check_api_docs_sh = find_program('tools/meson-check-api-docs.sh')
+check_api_docs_sh = find_program('tools/check-api-docs.sh')
run_target(
'check-api-docs',
depends : [man, libsystemd, libudev],
- command : [meson_check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
+ command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()])
############################################################
watchdog_opt = service_watchdog == '' ? 'disabled' : service_watchdog
['SMACK'],
['zlib'],
['xz'],
+ ['zstd'],
['lz4'],
['bzip2'],
['ACL'],
['openssl'],
['libcurl'],
['idn'],
+ ['initrd'],
['libidn2'],
['libidn'],
['libiptc'],
description : 'path to telinit')
option('rc-local', type : 'string',
value : '/etc/rc.local')
+option('initrd', type: 'boolean',
+ description : 'install services for use when running systemd in initrd')
option('quotaon-path', type : 'string', description : 'path to quotaon')
option('quotacheck-path', type : 'string', description : 'path to quotacheck')
option('libcurl', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libcurl support')
option('idn', type : 'boolean',
- description : 'use IDN when printing host names')
+ description : 'use IDN when printing hostnames')
option('libidn2', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'libidn2 support')
option('libidn', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'xz compression support')
option('lz4', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'lz4 compression support')
+option('zstd', type : 'combo', choices : ['auto', 'true', 'false'],
+ description : 'zstd compression support')
option('xkbcommon', type : 'combo', choices : ['auto', 'true', 'false'],
description : 'xkbcommon keymap support')
option('pcre2', type : 'combo', choices : ['auto', 'true', 'false'],
msgstr "Неабходна аўтэнтыфікацыя для перачытання стану systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Усталяваць імя вузла"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Неабходна аўтэнтыфікацыя для ўсталявання імя вузла."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Усталяваць статычнае імя вузла"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Неабходна аўтэнтыфікацыя для ўсталявання як статычнага так і прыгожага імя "
"вузла."
msgstr "Nieabchodna aŭtentyfikacyja dlia pieračytannia stanu systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Ustaliavać imia vuzla"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia imia vuzla."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Ustaliavać statyčnaje imia vuzla"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia jak statyčnaha tak i "
"pryhožaha imia vuzla."
msgstr "За презареждане на състоянието на systemd е необходима идентификация."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Задаване на име на машината"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "За задаване на име на локалната машина е необходима идентификация."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Задаване на статично име на машината"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"За задаване на статично име на локалната машина е необходима идентификация."
msgstr "Es requereix autenticació per tornar a carregar l'estat de systemd."
#: src/hostname/org.freedesktop.hostname1.policy:22
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Estableix el nom d'amfitrió"
#: src/hostname/org.freedesktop.hostname1.policy:23
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Es requereix autenticació per establir el nom d'amfitrió local."
#: src/hostname/org.freedesktop.hostname1.policy:32
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Estableix el nom d'amfitrió estàtic"
#: src/hostname/org.freedesktop.hostname1.policy:33
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Es requereix autenticació per establir el nom d'amfitrió local configurat "
"estàticament, així com el nom bonic d'amfitrió."
msgstr "Pro změnu hesla domovského adresáře uživatele je vyžadováno ověření."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Nastavit název stroje"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Pro nastavení lokálního názvu stroje je vyžadováno ověření."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Nastavit statický název stroje"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Pro nastavení staticky konfigurovaného názvu lokálního stroje, stejně tak "
"pro změnu uživatelsky přívětivého jména je vyžadováno ověření."
msgstr "Autentificering er nødvendig for at genindlæse systemd tilstanden."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Sæt værtsnavn"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Autentificering er nødvendig for at sætte værtsnavn."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Sæt statisk værstnavn"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Autentificering er nødvendig for at sætte det statisk konfigurerede lokale "
"værtsnavn, lige så vel som det pæne værtsnavn."
msgstr "Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Rechnername festlegen"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Legitimierung ist zum Festlegen des lokalen Rechnernamens notwendig"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Statischen Rechnernamen festlegen"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Authentifizierung ist erforderlich, um den statisch geänderten, lokalen "
"Rechnernamen, sowie den beschönigten Rechnernamen festzulegen."
msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Ορισμός ονόματος οικοδεσπότη"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Ορισμός στατικού ονόματος οικοδεσπότη"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Απαιτείται πιστοποίηση για να ορίσετε το στατικά ρυθμισμένο όνομα τοπικού "
"οικοδεσπότη, καθώς και το pretty όνομα οικοδεσπότη."
msgstr "Se requiere autenticación para recargar el estado de systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Establecer el nombre del equipo"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Se requiere autenticación para establecer el nombre del equipo local."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Establecer nombre estático del equipo"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Se requiere autenticación para establecer el nombre estático de equipo "
"local, así como el nombre visible del equipo."
"d'un utilisateur."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Définir le nom d'hôte"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Authentification requise pour définir le nom d'hôte local."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Définir le nom d'hôte statique"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Authentification requise pour définir le nom d'hôte local de manière "
"statique, tout comme le nom d'hôte familier."
msgstr "Requírese autenticación para recargar o estado de systemd."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Estabelecer o nome do equipo"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Requírese autenticación para estabelecer o nome local do equiupo."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Estabelecer o nome do equipo estático"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Requírese autenticación para estabelecer de forma o nome do equipo local "
"estabelecido de forma estática, así como o nome do equipo lexíbel por "
msgstr "Potrebna je ovjera za promjenu lozinke osobnog prostora korisnika."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Postavi naziv računala"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Potrebna je ovjera za postavljanje naziva lokalnog računala."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Postavi nepromjenjivi naziv račumala"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Potrebna je ovjera za postavljenje nepromjenjivog naziva lokalnog računala, "
"kao i prijatnog naziva računala."
msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Gépnév beállítása"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Hitelesítés szükséges a helyi gépnév beállításához."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Statikus gépnév beállítása"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Hitelesítés szükséges a statikusan megadott helyi gépnév, valamint a szép "
"gépnév beállításához."
msgstr "Otentikasi diperlukan untuk memuat ulang keadaan systemd."
#: src/hostname/org.freedesktop.hostname1.policy:22
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Setel nama host"
#: src/hostname/org.freedesktop.hostname1.policy:23
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Otentikasi diperlukan untuk menata nama host lokal."
#: src/hostname/org.freedesktop.hostname1.policy:32
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Setel nama host statik"
#: src/hostname/org.freedesktop.hostname1.policy:33
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Otentikasi diperlukan untuk menata nama host lokal yang dikonfigurasi "
"statik, maupun nama host cantik."
"dell'utente."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Configura il nome host"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Autenticazione richiesta per configurare il nome host locale."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Configura il nome host statico"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Autenticazione richiesta per configurare staticamente il nome host locale e "
"il nome host descrittivo."
msgstr "ユーザのホーム領域のパスワードを変更するには認証が必要です。"
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "ホスト名の設定"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "ホスト名を設定するには認証が必要です。"
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "静的なホスト名の設定"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr "静的なホスト名を設定するには認証が必要です。"
#: src/hostname/org.freedesktop.hostname1.policy:41
msgstr "systemd 상태를 다시 불러오려면 인증이 필요합니다."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "호스트 이름 설정"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "로컬 호스트 이름을 설정하려면 인증이 필요합니다."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "정적 호스트 이름 설정"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"로컬 호스트 이름을 모양새를 갖춘 호스트 이름 처럼 정적으로 설정하려면 인증"
"이 필요합니다."
msgstr "Norint iš naujo įkelti systemd būseną, reikia patvirtinti tapatybę."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Nustatyti serverio pavadinimą"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr ""
"Norint nustatyti vietinio serverio pavadinimą, reikia nustatyti tapatybę."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Nustatyti statinį serverio pavadinimą"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Norint nustatyti statiškai sukonfigūruotą serverio pavadinimą, o taip pat "
"lengvai įsimenamą serverio pavadinimą, reikia nustatyti tapatybę."
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2020-03-07 03:28+0000\n"
-"PO-Revision-Date: 2020-03-15 13:13+0100\n"
+"POT-Creation-Date: 2020-05-01 15:36+0000\n"
+"PO-Revision-Date: 2020-05-03 13:50+0200\n"
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
"Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
"Language: pl\n"
"użytkownika."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Ustawienie nazwy komputera"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Wymagane jest uwierzytelnienie, aby ustawić nazwę lokalnego komputera."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Ustawienie statycznej nazwy komputera"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ustawić statycznie skonfigurowaną nazwę "
"lokalnego komputera, a także jego nazwę czytelną dla człowieka."
"Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
"czasu przez sieć."
-#: src/core/dbus-unit.c:356
+#: src/core/dbus-unit.c:358
msgid "Authentication is required to start '$(unit)'."
msgstr "Wymagane jest uwierzytelnienie, aby uruchomić jednostkę „$(unit)”."
-#: src/core/dbus-unit.c:357
+#: src/core/dbus-unit.c:359
msgid "Authentication is required to stop '$(unit)'."
msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać jednostkę „$(unit)”."
-#: src/core/dbus-unit.c:358
+#: src/core/dbus-unit.c:360
msgid "Authentication is required to reload '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ponownie wczytać jednostkę „$(unit)”."
-#: src/core/dbus-unit.c:359 src/core/dbus-unit.c:360
+#: src/core/dbus-unit.c:361 src/core/dbus-unit.c:362
msgid "Authentication is required to restart '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ponownie uruchomić jednostkę „$(unit)”."
-#: src/core/dbus-unit.c:532
+#: src/core/dbus-unit.c:534
msgid ""
"Authentication is required to send a UNIX signal to the processes of "
"'$(unit)'."
"Wymagane jest uwierzytelnienie, aby wysłać sygnał uniksowy do procesów "
"jednostki „$(unit)”."
-#: src/core/dbus-unit.c:563
+#: src/core/dbus-unit.c:565
msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby przywrócić stan „failed” (niepowodzenia) "
"jednostki „$(unit)”."
-#: src/core/dbus-unit.c:596
+#: src/core/dbus-unit.c:598
msgid "Authentication is required to set properties on '$(unit)'."
msgstr ""
"Wymagane jest uwierzytelnienie, aby ustawić właściwości jednostki „$(unit)”."
-#: src/core/dbus-unit.c:705
+#: src/core/dbus-unit.c:707
msgid ""
"Authentication is required to delete files and directories associated with "
"'$(unit)'."
"Wymagane jest uwierzytelnienie, aby usunąć pliki i katalogi powiązane "
"z jednostką „$(unit)”."
+#: src/core/dbus-unit.c:756
+msgid ""
+"Authentication is required to freeze or thaw the processes of '$(unit)' unit."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zamrozić lub odmrozić procesy jednostki "
+"„$(unit)”."
+
#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
#~ msgstr ""
#~ "Naciśnięcie klawiszy Ctrl+C anuluje wszystkie trwające procesy "
msgstr "É necessária autenticação para recarregar o estado do sistema."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Definir nome de máquina"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "É necessária autenticação para definir nome de máquina local."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Definir nome estático de máquina"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"É necessária autenticação para definir o nome de máquina local configurado "
"estaticamente, assim como o nome apresentável de máquina."
msgstr "Autentificarea este necesară pentru a reîncărca starea systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Stabilește numele de server"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Autentificarea este necesară pentru a stabili numele de server local."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Stabilește numele de server static"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Autentificarea este necesara pentru a stabili numele de server static "
"configurat local, precum și numele lung de server."
" пройти аутентификацию."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Настроить имя компьютера"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Чтобы настроить имя компьютера, необходимо пройти аутентификацию."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Настроить статическое имя компьютера"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Чтобы настроить статическое имя компьютера, а также его «красивое» имя, "
"необходимо пройти аутентификацию."
"Vyžaduje sa overenie totožnosti na znovu načítanie stavu systému systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Nastavenie názvu hostiteľa"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Vyžaduje sa overenie totožnosti na nastavenie názvu hostiteľa."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Nastavenie nemenného názvu hostiteľa"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Vyžaduje sa overenie totožnosti na nastavenie pevne určeného názvu miestneho "
"hostiteľa, známeho ako zrozumiteľný názov hostiteľa."
"Потребно је да се идентификујете да бисте поново учитали стање систем-деа."
#: src/hostname/org.freedesktop.hostname1.policy.in:22
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Постави назив машине"
#: src/hostname/org.freedesktop.hostname1.policy.in:23
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Потребно је да се идентификујете да бисте поставили назив машине."
#: src/hostname/org.freedesktop.hostname1.policy.in:32
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Постави статички назив машине"
#: src/hostname/org.freedesktop.hostname1.policy.in:33
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Потребно је да се идентификујете да бисте поставили статички назив машине и "
"да бисте поставили леп назив машине."
msgstr "Autentisering krävs för att läsa om tillståndet för systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Ange värdnamn"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Autentisering krävs för att ställa in lokalt värdnamn."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Ange statiskt värdnamn"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Autentisering krävs för att ställa in det statiskt konfigurerade lokala "
"värdnamnet såväl som det stiliga värdnamnet."
msgstr "systemd durumunu yeniden yüklemek kimlik doğrulaması gerektiriyor."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Makine adını ayarla"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Yerel makine adını ayarlamak kimlik doğrulaması gerektiriyor."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Statik makine adı ayarla"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Statik olarak yapılandırılmış konak makine adını ve yerel makine adını "
"ayarlamak kimlik doğrulaması gerektiriyor."
"розпізнавання."
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "Встановити назву вузла"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "Потрібна автентифікація, щоб встановити назву локального вузла."
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "Встановити статичну назву вузла"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr ""
"Потрібна автентифікація, щоб вказати статично налаштовану назву локального "
"вузла, так само й форматовану."
msgstr "重新载入 systemd 状态需要认证。"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
+msgid "Set hostname"
msgstr "设置主机名"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "设置本地主机名需要认证。"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "设置静态主机名"
# For pretty hostname, the zh_CN/zh_TW translation should be discussed again.
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
#, fuzzy
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr "设置静态本地主机名或美观主机名需要认证。"
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
msgstr "重新載入 systemd 狀態需要驗證。"
#: src/hostname/org.freedesktop.hostname1.policy:20
-msgid "Set host name"
+msgid "Set hostname"
msgstr "設定主機名稱"
#: src/hostname/org.freedesktop.hostname1.policy:21
-msgid "Authentication is required to set the local host name."
+msgid "Authentication is required to set the local hostname."
msgstr "設定主機名稱需要驗證。"
#: src/hostname/org.freedesktop.hostname1.policy:30
-msgid "Set static host name"
+msgid "Set static hostname"
msgstr "設定靜態主機名稱"
#: src/hostname/org.freedesktop.hostname1.policy:31
msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
+"Authentication is required to set the statically configured local hostname, "
+"as well as the pretty hostname."
msgstr "設定靜態預先設定或 pretty 本地主機名稱需要身份驗證。"
#: src/hostname/org.freedesktop.hostname1.policy:41
apt-get -y dist-upgrade
apt-get install -y eatmydata
# The following four are needed as long as these deps are not covered by Debian's own packaging
-apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev libpwquality-dev
+apt-get install -y fdisk libfdisk-dev libp11-kit-dev libssl-dev libpwquality-dev
apt-get purge --auto-remove -y unattended-upgrades
systemctl unmask systemd-networkd
systemctl enable systemd-networkd
git checkout FETCH_HEAD debian
# craft changelog
- UPSTREAM_VER=$(git describe | sed 's/^v//')
+ UPSTREAM_VER=$(git describe | sed 's/^v//;s/-/./g')
cat << EOF > debian/changelog.new
-systemd (${UPSTREAM_VER}-0) UNRELEASED; urgency=low
+systemd (${UPSTREAM_VER}.0) UNRELEASED; urgency=low
* Automatic build for upstream test
_systemctl_failed_units() {_sys_failed_units=( ${${(f)"$(__systemctl list-units --state=failed "$PREFIX*" )"}%% *} ) }
(( $+functions[_systemctl_unit_state] )) ||
- _systemctl_unit_state() { typeset -gA _sys_unit_state; _sys_unit_state=( $(__systemctl list-unit-files "$PREFIX*" ) ) }
+ _systemctl_unit_state() {
+ setopt localoptions extendedglob
+ typeset -gA _sys_unit_state
+ _sys_unit_state=( ${=${${(f)"$(__systemctl list-unit-files "$PREFIX*" )"}%%[[:space:]]#}% *} )
+ }
local fun
# Completion functions for ALL_UNITS
_describe -t state 'state' _states || compadd "$@"
}
+(( $+functions[_systemd-analyze_cat-config] )) ||
+ _systemd-analyze_cat-config() {
+ _files -W '(/run/systemd/ /etc/systemd/ /usr/lib/systemd/)' -P 'systemd/'
+ }
+
+(( $+functions[_systemd-analyze_security] )) ||
+ _systemd-analyze_security() {
+ _sd_unit_files
+ }
+
(( $+functions[_systemd-analyze_commands] )) ||
_systemd-analyze_commands(){
local -a _systemd_analyze_cmds
'plot:Output SVG graphic showing service initialization'
'dot:Dump dependency graph (in dot(1) format)'
'dump:Dump server status'
+ 'cat-config:Cat systemd config files'
+ 'unit-files:List files and symlinks for units'
'unit-paths:List unit load paths'
- 'log-level:Get/set systemd log threshold'
- 'log-target:Get/set systemd log target'
- 'service-watchdogs:Get/set service watchdog status'
+ 'exit-status:List known exit statuses'
'syscall-filter:List syscalls in seccomp filter'
+ 'condition:Evaluate Condition*= and Assert*= assignments'
'verify:Check unit files for correctness'
'calendar:Validate repetitive calendar time events'
+ 'timestamp:Parse a systemd syntax timestamp'
+ 'timespan:Parse a systemd syntax timespan'
+ 'security:Analyze security settings of a service'
+ # 'log-level:Get/set systemd log threshold'
+ # 'log-target:Get/set systemd log target'
+ # 'service-watchdogs:Get/set service watchdog status'
)
if (( CURRENT == 1 )); then
{ "ConditionPathIsSymbolicLink", config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK },
{ "ConditionPathIsMountPoint", config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT },
{ "ConditionPathIsReadWrite", config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE },
+ { "ConditionPathIsEncrypted", config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED },
{ "ConditionDirectoryNotEmpty", config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY },
{ "ConditionFileNotEmpty", config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY },
{ "ConditionFileIsExecutable", config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE },
{ "AssertPathIsSymbolicLink", config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK },
{ "AssertPathIsMountPoint", config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT },
{ "AssertPathIsReadWrite", config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE },
+ { "AssertPathIsEncrypted", config_parse_unit_condition_path, CONDITION_PATH_IS_ENCRYPTED },
{ "AssertDirectoryNotEmpty", config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY },
{ "AssertFileNotEmpty", config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY },
{ "AssertFileIsExecutable", config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE },
return r;
}
- r = condition_test_list(u->asserts, assert_type_to_string, log_helper, u);
+ r = condition_test_list(u->asserts, environ, assert_type_to_string, log_helper, u);
if (u->asserts)
log_notice("Asserts %s.", r > 0 ? "succeeded" : "failed");
- q = condition_test_list(u->conditions, condition_type_to_string, log_helper, u);
+ q = condition_test_list(u->conditions, environ, condition_type_to_string, log_helper, u);
if (u->conditions)
log_notice("Conditions %s.", q > 0 ? "succeeded" : "failed");
strv_free(i->supplementary_groups);
strv_free(i->system_call_architectures);
- set_free_free(i->system_call_filter);
+ set_free(i->system_call_filter);
}
static bool security_info_runs_privileged(const struct security_info *i) {
if (r == 0)
break;
- r = set_ensure_allocated(&info->system_call_filter, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put_strdup(info->system_call_filter, name);
+ r = set_put_strdup(&info->system_call_filter, name);
if (r < 0)
return r;
}
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits",
- &error, &reply,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnits",
- &error,
- &reply,
- "");
+ r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, "");
if (r < 0)
log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
assert(bus);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Dump",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, "Dump", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to issue method call Dump: %s", bus_error_message(&error, r));
if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD))
return dump_fallback(bus);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "DumpByFileDescriptor",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, "DumpByFileDescriptor", &error, &reply, NULL);
if (r < 0) {
/* fall back to Dump if DumpByFileDescriptor is not supported */
if (!IN_SET(r, -EACCES, -EBADR))
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
- r = sd_bus_set_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogLevel",
- &error,
- "s",
- argv[1]);
+ r = bus_set_property(bus, bus_systemd_mgr, "LogLevel", &error, "s", argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogLevel",
- &error,
- &level);
+ r = bus_get_property_string(bus, bus_systemd_mgr, "LogLevel", &error, &level);
if (r < 0)
return log_error_errno(r, "Failed to get log level: %s", bus_error_message(&error, r));
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
- r = sd_bus_set_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogTarget",
- &error,
- "s",
- argv[1]);
+ r = bus_set_property(bus, bus_systemd_mgr, "LogTarget", &error, "s", argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogTarget",
- &error,
- &target);
+ r = bus_get_property_string(bus, bus_systemd_mgr, "LogTarget", &error, &target);
if (r < 0)
return log_error_errno(r, "Failed to get log target: %s", bus_error_message(&error, r));
#if HAVE_SECCOMP
static int load_kernel_syscalls(Set **ret) {
- _cleanup_(set_free_freep) Set *syscalls = NULL;
+ _cleanup_set_free_ Set *syscalls = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
continue;
- r = set_ensure_allocated(&syscalls, &string_hash_ops);
- if (r < 0)
- return log_oom();
-
- r = set_put_strdup(syscalls, e);
+ r = set_put_strdup(&syscalls, e);
if (r < 0)
return log_error_errno(r, "Failed to add system call to list: %m");
}
(void) pager_open(arg_pager_flags);
if (strv_isempty(strv_skip(argv, 1))) {
- _cleanup_(set_free_freep) Set *kernel = NULL;
+ _cleanup_set_free_ Set *kernel = NULL;
int i, k;
k = load_kernel_syscalls(&kernel);
if (argc == 1) {
/* get ServiceWatchdogs */
- r = sd_bus_get_property_trivial(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ServiceWatchdogs",
- &error,
- 'b',
- &b);
+ r = bus_get_property_trivial(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, 'b', &b);
if (r < 0)
return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
if (b < 0)
return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
- r = sd_bus_set_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ServiceWatchdogs",
- &error,
- "b",
- b);
+ r = bus_set_property(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, "b", b);
if (r < 0)
return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
}
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/file.h>
#include <unistd.h>
#include "alloc-util.h"
*ret = d;
return 0;
}
+ if (errno != ENOENT)
+ return -errno;
/* If it is a partition find the originating device */
xsprintf_sys_block_path(p, "/partition", d);
return 1;
}
+
+int lock_whole_block_device(dev_t devt, int operation) {
+ _cleanup_free_ char *whole_node = NULL;
+ _cleanup_close_ int lock_fd = -1;
+ dev_t whole_devt;
+ int r;
+
+ /* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
+
+ r = block_get_whole_disk(devt, &whole_devt);
+ if (r < 0)
+ return r;
+
+ r = device_path_make_major_minor(S_IFBLK, whole_devt, &whole_node);
+ if (r < 0)
+ return r;
+
+ lock_fd = open(whole_node, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+ if (lock_fd < 0)
+ return -errno;
+
+ if (flock(lock_fd, operation) < 0)
+ return -errno;
+
+ return TAKE_FD(lock_fd);
+}
int get_block_device(const char *path, dev_t *dev);
int get_block_device_harder(const char *path, dev_t *dev);
+
+int lock_whole_block_device(dev_t devt, int operation);
return -errno;
if (!S_ISBLK(st.st_mode))
- return -ENODEV;
+ return -ENOTBLK;
if (major(st.st_rdev) == 0)
return -ENODEV;
FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
_cleanup_free_ char *p = NULL;
const struct btrfs_root_ref *ref;
- struct btrfs_ioctl_ino_lookup_args ino_args;
btrfs_ioctl_search_args_set(&args, sh);
if (!p)
return -ENOMEM;
- zero(ino_args);
- ino_args.treeid = subvol_id;
- ino_args.objectid = htole64(ref->dirid);
+ struct btrfs_ioctl_ino_lookup_args ino_args = {
+ .treeid = subvol_id,
+ .objectid = htole64(ref->dirid),
+ };
if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
return -errno;
FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
_cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
- struct btrfs_ioctl_ino_lookup_args ino_args;
const struct btrfs_root_ref *ref;
_cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
if (!p)
return -ENOMEM;
- zero(ino_args);
- ino_args.treeid = old_subvol_id;
- ino_args.objectid = htole64(ref->dirid);
+ struct btrfs_ioctl_ino_lookup_args ino_args = {
+ .treeid = old_subvol_id,
+ .objectid = htole64(ref->dirid),
+ };
if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
return -errno;
#define _LZ4_FEATURE_ "-LZ4"
#endif
+#if HAVE_ZSTD
+#define _ZSTD_FEATURE_ "+ZSTD"
+#else
+#define _ZSTD_FEATURE_ "-ZSTD"
+#endif
+
#if HAVE_SECCOMP
#define _SECCOMP_FEATURE_ "+SECCOMP"
#else
_ACL_FEATURE_ " " \
_XZ_FEATURE_ " " \
_LZ4_FEATURE_ " " \
+ _ZSTD_FEATURE_ " " \
_SECCOMP_FEATURE_ " " \
_BLKID_FEATURE_ " " \
_ELFUTILS_FEATURE_ " " \
return enabled;
}
+bool cg_freezer_supported(void) {
+ static thread_local int supported = -1;
+
+ if (supported >= 0)
+ return supported;
+
+ supported = cg_all_unified() > 0 && access("/sys/fs/cgroup/init.scope/cgroup.freeze", F_OK) == 0;
+
+ return supported;
+}
+
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
_cleanup_free_ char *fs = NULL;
int r;
return 0;
}
-int cg_get_keyed_attribute(
+int cg_get_keyed_attribute_full(
const char *controller,
const char *path,
const char *attribute,
char **keys,
- char **ret_values) {
+ char **ret_values,
+ CGroupKeyMode mode) {
_cleanup_free_ char *filename = NULL, *contents = NULL;
const char *p;
* all keys to retrieve. The 'ret_values' parameter should be passed as string size with the same number of
* entries as 'keys'. On success each entry will be set to the value of the matching key.
*
- * If the attribute file doesn't exist at all returns ENOENT, if any key is not found returns ENXIO. */
+ * If the attribute file doesn't exist at all returns ENOENT, if any key is not found returns ENXIO. If mode
+ * is set to GG_KEY_MODE_GRACEFUL we ignore missing keys and return those that were parsed successfully. */
r = cg_get_path(controller, path, attribute, &filename);
if (r < 0)
p += strspn(p, NEWLINE);
}
+ if (mode & CG_KEY_MODE_GRACEFUL)
+ goto done;
+
r = -ENXIO;
fail:
done:
memcpy(ret_values, v, sizeof(char*) * n);
+ if (mode & CG_KEY_MODE_GRACEFUL)
+ return n_done;
+
return 0;
}
unified_cache = CGROUP_UNIFIED_NONE;
}
}
+ } else if (F_TYPE_EQUAL(fs.f_type, SYSFS_MAGIC)) {
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
+ "No filesystem is currently mounted on /sys/fs/cgroup.");
} else
return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
"Unknown filesystem type %llx mounted on /sys/fs/cgroup.",
int cg_rmdir(const char *controller, const char *path);
+typedef enum {
+ CG_KEY_MODE_GRACEFUL = 1 << 0,
+} CGroupKeyMode;
+
int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
-int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values);
+int cg_get_keyed_attribute_full(const char *controller, const char *path, const char *attribute, char **keys, char **values, CGroupKeyMode mode);
+
+static inline int cg_get_keyed_attribute(
+ const char *controller,
+ const char *path,
+ const char *attribute,
+ char **keys,
+ char **ret_values) {
+ return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, 0);
+}
+
+static inline int cg_get_keyed_attribute_graceful(
+ const char *controller,
+ const char *path,
+ const char *attribute,
+ char **keys,
+ char **ret_values) {
+ return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, CG_KEY_MODE_GRACEFUL);
+}
int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret);
int cg_kernel_controllers(Set **controllers);
bool cg_ns_supported(void);
+bool cg_freezer_supported(void);
int cg_all_unified(void);
int cg_hybrid_unified(void);
/* Is this a masking entry? */
if ((flags & CONF_FILES_FILTER_MASKED))
if (null_or_empty(&st)) {
+ assert(masked);
+
/* Mark this one as masked */
- r = set_put_strdup(masked, de->d_name);
+ r = set_put_strdup(&masked, de->d_name);
if (r < 0)
return r;
#if ENABLE_EFI
+/* Reads from efivarfs sometimes fail with EINTR. Retry that many times. */
+#define EFI_N_RETRIES 5
+#define EFI_RETRY_DELAY (50 * USEC_PER_MSEC)
+
char* efi_variable_path(sd_id128_t vendor, const char *name) {
char *p;
return -ENOMEM;
if (!ret_value && !ret_size && !ret_attribute) {
- /* If caller is not interested in anything, just check if the variable exists and is readable
- * to us. */
+ /* If caller is not interested in anything, just check if the variable exists and is
+ * readable. */
if (access(p, R_OK) < 0)
return -errno;
fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
- return -errno;
+ return log_debug_errno(errno, "open(\"%s\") failed: %m", p);
if (fstat(fd, &st) < 0)
return -errno;
return -E2BIG;
if (ret_value || ret_attribute) {
- n = read(fd, &a, sizeof(a));
- if (n < 0)
- return -errno;
+ /* The kernel ratelimits reads from the efivarfs because EFI is inefficient, and we'll
+ * occasionally fail with EINTR here. A slowdown is better than a failure for us, so
+ * retry a few times and eventually fail with -EBUSY.
+ *
+ * See https://github.com/torvalds/linux/blob/master/fs/efivarfs/file.c#L75
+ * and
+ * https://github.com/torvalds/linux/commit/bef3efbeb897b56867e271cdbc5f8adaacaeb9cd.
+ */
+ for (unsigned try = 0;; try++) {
+ n = read(fd, &a, sizeof(a));
+ if (n >= 0)
+ break;
+ log_debug_errno(errno, "read from \"%s\" failed: %m", p);
+ if (errno != EINTR)
+ return -errno;
+ if (try >= EFI_N_RETRIES)
+ return -EBUSY;
+ usleep(EFI_RETRY_DELAY);
+ }
+
if (n != sizeof(a))
return -EIO;
}
}
bool is_efi_boot(void) {
- if (detect_container() > 0)
- return false;
+ static int cache = -1;
- return access("/sys/firmware/efi/", F_OK) >= 0;
+ if (cache < 0) {
+ if (detect_container() > 0)
+ cache = false;
+ else
+ cache = access("/sys/firmware/efi/", F_OK) >= 0;
+ }
+
+ return cache;
}
static int read_flag(const char *varname) {
}
bool is_efi_secure_boot(void) {
- return read_flag("SecureBoot") > 0;
+ static int cache = -1;
+
+ if (cache < 0)
+ cache = read_flag("SecureBoot");
+
+ return cache > 0;
}
bool is_efi_secure_boot_setup_mode(void) {
- return read_flag("SetupMode") > 0;
+ static int cache = -1;
+
+ if (cache < 0)
+ cache = read_flag("SetupMode");
+
+ return cache > 0;
}
int systemd_efi_options_variable(char **line) {
return 0;
}
+ /* In SecureBoot mode this is probably not what you want. As your cmdline is cryptographically signed
+ * like when using Type #2 EFI Unified Kernel Images (https://systemd.io/BOOT_LOADER_SPECIFICATION/)
+ * The user's intention is then that the cmdline should not be modified. You want to make sure that
+ * the system starts up as exactly specified in the signed artifact.
+ *
+ * (NB: to make testing purposes we still check the $SYSTEMD_EFI_OPTIONS env var above, even when in
+ * SecureBoot mode.) */
+ if (is_efi_secure_boot()) {
+ _cleanup_free_ char *k;
+
+ k = efi_variable_path(EFI_VENDOR_SYSTEMD, "SystemdOptions");
+ if (!k)
+ return -ENOMEM;
+
+ /* Let's be helpful with the returned error and check if the variable exists at all. If it
+ * does, let's return a recognizable error (EPERM), and if not ENODATA. */
+
+ if (access(k, F_OK) < 0)
+ return errno == ENOENT ? -ENODATA : -errno;
+
+ return -EPERM;
+ }
+
r = efi_get_variable_string(EFI_VENDOR_SYSTEMD, "SystemdOptions", line);
if (r == -ENOENT)
return -ENODATA;
#include "path-util.h"
#include "process-util.h"
#include "socket-util.h"
+#include "stat-util.h"
#include "stdio-util.h"
-#include "util.h"
#include "tmpfile-util.h"
+#include "util.h"
/* The maximum number of iterations in the loop to close descriptors in the fallback case
* when /proc/self/fd/ is inaccessible. */
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
new_fd = open(procfs_path, flags);
- if (new_fd < 0)
- return -errno;
+ if (new_fd < 0) {
+ if (errno != ENOENT)
+ return -errno;
+
+ if (proc_mounted() == 0)
+ return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
+
+ return -ENOENT;
+ }
return new_fd;
}
break;
}
- if (errno != -EINTR)
+ if (errno != EINTR)
return -errno;
}
#include <unistd.h>
#include "alloc-util.h"
+#include "blockdev-util.h"
#include "dirent-util.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "locale-util.h"
#include "log.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "random-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
* fchownat() does. */
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
- if (chmod(procfs_path, m) < 0)
- return -errno;
+ if (chmod(procfs_path, m) < 0) {
+ if (errno != ENOENT)
+ return -errno;
+
+ if (proc_mounted() == 0)
+ return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
+
+ return -ENOENT;
+ }
return 0;
}
(void) unlink_noerrno(*p);
}
-int unlinkat_deallocate(int fd, const char *name, int flags) {
+int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
_cleanup_close_ int truncate_fd = -1;
struct stat st;
off_t l, bs;
+ assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
+
/* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
* link to it. This is useful to ensure that other processes that might have the file open for reading won't be
* able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up
* Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the
* primary job – to delete the file – is accomplished. */
- if ((flags & AT_REMOVEDIR) == 0) {
+ if (!FLAGS_SET(flags, UNLINK_REMOVEDIR)) {
truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
if (truncate_fd < 0) {
}
}
- if (unlinkat(fd, name, flags) < 0)
+ if (unlinkat(fd, name, FLAGS_SET(flags, UNLINK_REMOVEDIR) ? AT_REMOVEDIR : 0) < 0)
return -errno;
if (truncate_fd < 0) /* Don't have a file handle, can't do more ☹️ */
return 0;
}
- if (!S_ISREG(st.st_mode) || st.st_blocks == 0 || st.st_nlink > 0)
+ if (!S_ISREG(st.st_mode))
+ return 0;
+
+ if (FLAGS_SET(flags, UNLINK_ERASE) && st.st_size > 0 && st.st_nlink == 0) {
+ uint64_t left = st.st_size;
+ char buffer[64 * 1024];
+
+ /* If erasing is requested, let's overwrite the file with random data once before deleting
+ * it. This isn't going to give you shred(1) semantics, but hopefully should be good enough
+ * for stuff backed by tmpfs at least.
+ *
+ * Note that we only erase like this if the link count of the file is zero. If it is higer it
+ * is still linked by someone else and we'll leave it to them to remove it securely
+ * eventually! */
+
+ random_bytes(buffer, sizeof(buffer));
+
+ while (left > 0) {
+ ssize_t n;
+
+ n = write(truncate_fd, buffer, MIN(sizeof(buffer), left));
+ if (n < 0) {
+ log_debug_errno(errno, "Failed to erase data in file '%s', ignoring.", name);
+ break;
+ }
+
+ assert(left >= (size_t) n);
+ left -= n;
+ }
+
+ /* Let's refresh metadata */
+ if (fstat(truncate_fd, &st) < 0) {
+ log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
+ return 0;
+ }
+ }
+
+ /* Don't dallocate if there's nothing to deallocate or if the file is linked elsewhere */
+ if (st.st_blocks == 0 || st.st_nlink > 0)
return 0;
/* If this is a regular file, it actually took up space on disk and there are no other links it's time to
return fd;
}
+
+static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
+ _cleanup_free_ char *p = NULL, *uuids = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
+ int r, found_encrypted = false;
+
+ assert(sysfs_path);
+
+ if (depth_left == 0)
+ return -EINVAL;
+
+ p = path_join(sysfs_path, "dm/uuid");
+ if (!p)
+ return -ENOMEM;
+
+ r = read_one_line_file(p, &uuids);
+ if (r != -ENOENT) {
+ if (r < 0)
+ return r;
+
+ /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
+ if (startswith(uuids, "CRYPT-"))
+ return true;
+ }
+
+ /* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
+ * subdir. */
+
+ p = mfree(p);
+ p = path_join(sysfs_path, "slaves");
+ if (!p)
+ return -ENOMEM;
+
+ d = opendir(p);
+ if (!d) {
+ if (errno == ENOENT) /* Doesn't have slaves */
+ return false;
+
+ return -errno;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *q = NULL;
+ struct dirent *de;
+
+ errno = 0;
+ de = readdir_no_dot(d);
+ if (!de) {
+ if (errno != 0)
+ return -errno;
+
+ break; /* No more slaves */
+ }
+
+ q = path_join(p, de->d_name);
+ if (!q)
+ return -ENOMEM;
+
+ r = blockdev_is_encrypted(q, depth_left - 1);
+ if (r < 0)
+ return r;
+ if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
+ return false;
+
+ found_encrypted = true;
+ }
+
+ return found_encrypted;
+}
+
+int path_is_encrypted(const char *path) {
+ char p[SYS_BLOCK_PATH_MAX(NULL)];
+ dev_t devt;
+ int r;
+
+ r = get_block_device(path, &devt);
+ if (r < 0)
+ return r;
+ if (r == 0) /* doesn't have a block device */
+ return false;
+
+ xsprintf_sys_block_path(p, NULL, devt);
+
+ return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
+}
int access_fd(int fd, int mode);
void unlink_tempfilep(char (*p)[]);
-int unlinkat_deallocate(int fd, const char *name, int flags);
+
+typedef enum UnlinkDeallocateFlags {
+ UNLINK_REMOVEDIR = 1 << 0,
+ UNLINK_ERASE = 1 << 1,
+} UnlinkDeallocateFlags;
+
+int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags);
int fsync_directory_of_file(int fd);
int fsync_full(int fd);
int syncfs_path(int atfd, const char *path);
int open_parent(const char *path, int flags, mode_t mode);
+
+int path_is_encrypted(const char *path);
return true;
}
-int glob_extend(char ***strv, const char *path) {
+int glob_extend(char ***strv, const char *path, int flags) {
_cleanup_globfree_ glob_t g = {};
int k;
- k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
+ k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE|flags, &g);
if (k < 0)
return k;
int safe_glob(const char *path, int flags, glob_t *pglob);
int glob_exists(const char *path);
-int glob_extend(char ***strv, const char *path);
+int glob_extend(char ***strv, const char *path, int flags);
#define _cleanup_globfree_ _cleanup_(globfree)
}
DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
+ char, string_hash_func, string_compare_func, free);
DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
char, string_hash_func, string_compare_func, free,
char, free);
void string_hash_func(const char *p, struct siphash *state);
#define string_compare_func strcmp
extern const struct hash_ops string_hash_ops;
+extern const struct hash_ops string_hash_ops_free;
extern const struct hash_ops string_hash_ops_free_free;
void path_hash_func(const char *p, struct siphash *state);
return r;
_cleanup_free_ char *kdup = NULL, *vdup = NULL;
+
kdup = strdup(k);
- vdup = strdup(v);
- if (!kdup || !vdup)
+ if (!kdup)
return -ENOMEM;
+ if (v) {
+ vdup = strdup(v);
+ if (!vdup)
+ return -ENOMEM;
+ }
+
r = hashmap_put(*h, kdup, vdup);
if (r < 0) {
- if (r == -EEXIST && streq(v, hashmap_get(*h, kdup)))
+ if (r == -EEXIST && streq_ptr(v, hashmap_get(*h, kdup)))
return 0;
return r;
}
- assert(r > 0); /* 0 would mean vdup is already in the hashmap, which cannot be */
- kdup = vdup = NULL;
+ /* 0 with non-null vdup would mean vdup is already in the hashmap, which cannot be */
+ assert(vdup == NULL || r > 0);
+ if (r > 0)
+ kdup = vdup = NULL;
- return 0;
+ return r;
}
-int set_put_strdup(Set *s, const char *p) {
+int set_put_strdup(Set **s, const char *p) {
char *c;
+ int r;
assert(s);
assert(p);
- if (set_contains(s, (char*) p))
+ r = set_ensure_allocated(s, &string_hash_ops_free);
+ if (r < 0)
+ return r;
+
+ if (set_contains(*s, (char*) p))
return 0;
c = strdup(p);
if (!c)
return -ENOMEM;
- return set_consume(s, c);
+ return set_consume(*s, c);
}
-int set_put_strdupv(Set *s, char **l) {
+int set_put_strdupv(Set **s, char **l) {
int n = 0, r;
char **i;
#include "hostname-util.h"
#include "macro.h"
#include "string-util.h"
+#include "strv.h"
bool hostname_is_set(void) {
struct utsname u;
if (isempty(u.nodename))
return false;
- /* This is the built-in kernel default host name */
+ /* This is the built-in kernel default hostname */
if (streq(u.nodename, "(none)"))
return false;
char* gethostname_malloc(void) {
struct utsname u;
+ const char *s;
/* This call tries to return something useful, either the actual hostname
* or it makes something up. The only reason it might fail is OOM.
assert_se(uname(&u) >= 0);
- if (isempty(u.nodename) || streq(u.nodename, "(none)"))
- return strdup(FALLBACK_HOSTNAME);
+ s = u.nodename;
+ if (isempty(s) || streq(s, "(none)"))
+ s = FALLBACK_HOSTNAME;
- return strdup(u.nodename);
+ return strdup(s);
+}
+
+char* gethostname_short_malloc(void) {
+ struct utsname u;
+ const char *s;
+
+ /* Like above, but kills the FQDN part if present. */
+
+ assert_se(uname(&u) >= 0);
+
+ s = u.nodename;
+ if (isempty(s) || streq(s, "(none)") || s[0] == '.') {
+ s = FALLBACK_HOSTNAME;
+ assert(s[0] != '.');
+ }
+
+ return strndup(s, strcspn(s, "."));
}
int gethostname_strict(char **ret) {
}
/**
- * Check if s looks like a valid host name or FQDN. This does not do
+ * Check if s looks like a valid hostname or FQDN. This does not do
* full DNS validation, but only checks if the name is composed of
* allowed characters and the length is not above the maximum allowed
* by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
/* This tries to identify local host and domain names
* described in RFC6761 plus the redhatism of localdomain */
- return strcaseeq(hostname, "localhost") ||
- strcaseeq(hostname, "localhost.") ||
- strcaseeq(hostname, "localhost.localdomain") ||
- strcaseeq(hostname, "localhost.localdomain.") ||
- endswith_no_case(hostname, ".localhost") ||
- endswith_no_case(hostname, ".localhost.") ||
- endswith_no_case(hostname, ".localhost.localdomain") ||
- endswith_no_case(hostname, ".localhost.localdomain.");
+ return STRCASE_IN_SET(
+ hostname,
+ "localhost",
+ "localhost.",
+ "localhost.localdomain",
+ "localhost.localdomain.") ||
+ endswith_no_case(hostname, ".localhost") ||
+ endswith_no_case(hostname, ".localhost.") ||
+ endswith_no_case(hostname, ".localhost.localdomain") ||
+ endswith_no_case(hostname, ".localhost.localdomain.");
}
bool is_gateway_hostname(const char *hostname) {
bool hostname_is_set(void);
char* gethostname_malloc(void);
+char* gethostname_short_malloc(void);
int gethostname_strict(char **ret);
bool valid_ldh_char(char c) _const_;
}
if (r > 0) {
r = cg_get_attribute("memory", root, "memory.max", &value);
+ if (r == -ENOENT) /* Field does not exist on the system's top-level cgroup, hence don't
+ * complain. (Note that it might exist on our own root though, if we live
+ * in a cgroup namespace, hence check anyway instead of not even
+ * trying.) */
+ return mem;
if (r < 0) {
log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
return mem;
return true;
}
+int locale_is_installed(const char *name) {
+ if (!locale_is_valid(name))
+ return false;
+
+ if (STR_IN_SET(name, "C", "POSIX")) /* These ones are always OK */
+ return true;
+
+ _cleanup_(freelocalep) locale_t loc =
+ newlocale(LC_ALL_MASK, name, 0);
+ if (loc == (locale_t) 0)
+ return errno == ENOMEM ? -ENOMEM : false;
+
+ return true;
+}
+
void init_gettext(void) {
setlocale(LC_ALL, "");
textdomain(GETTEXT_PACKAGE);
int get_locales(char ***l);
bool locale_is_valid(const char *name);
+int locale_is_installed(const char *name);
#define _(String) gettext(String)
#define N_(String) String
#ifndef GRND_RANDOM
#define GRND_RANDOM 0x0002
#endif
+
+#ifndef GRND_INSECURE
+#define GRND_INSECURE 0x0004
+#endif
#include "process-util.h"
#include "stat-util.h"
#include "string-util.h"
+#include "strv.h"
int parse_boolean(const char *v) {
if (!v)
return -EINVAL;
- if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
+ if (STRCASE_IN_SET(v,
+ "1",
+ "yes",
+ "y",
+ "true",
+ "t",
+ "on"))
return 1;
- else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
+
+ if (STRCASE_IN_SET(v,
+ "0",
+ "no",
+ "n",
+ "false",
+ "f",
+ "off"))
return 0;
return -EINVAL;
if (!path)
return -ENOMEM;
- r = glob_extend(&names, path);
+ r = glob_extend(&names, path, 0);
if (r == -ENOENT)
continue;
if (r < 0)
return read_one_line_file("/proc/cmdline", ret);
}
-/* In SecureBoot mode this is probably not what you want. As your cmdline is
- * cryptographically signed like when using Type #2 EFI Unified Kernel Images
- * (https://systemd.io/BOOT_LOADER_SPECIFICATION/) The user's intention is then
- * that the cmdline should not be modified. You want to make sure that the
- * system starts up as exactly specified in the signed artifact. */
-static int systemd_options_variable(char **line) {
- if (is_efi_secure_boot())
- return -ENODATA;
-
- return systemd_efi_options_variable(line);
-}
-
static int proc_cmdline_extract_first(const char **p, char **ret_word, ProcCmdlineFlags flags) {
const char *q = *p;
int r;
/* We parse the EFI variable first, because later settings have higher priority. */
- r = systemd_options_variable(&line);
+ r = systemd_efi_options_variable(&line);
if (r < 0 && r != -ENODATA)
log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
return r;
line = mfree(line);
- r = systemd_options_variable(&line);
+ r = systemd_efi_options_variable(&line);
if (r == -ENODATA)
return false; /* Not found */
if (r < 0)
r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
if (r < 0)
return r;
- if (r == 0) {
+ if (r == 0) { /* key not specified at all */
*ret = false;
return 0;
}
- if (v) { /* parameter passed */
+ if (v) { /* key with parameter passed */
r = parse_boolean(v);
if (r < 0)
return r;
*ret = r;
- } else /* no parameter passed */
+ } else /* key without parameter passed */
*ret = true;
return 1;
#include "log.h"
typedef enum ProcCmdlineFlags {
- PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0,
- PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1,
- PROC_CMDLINE_RD_STRICT = 1 << 2,
+ PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */
+ PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */
+ PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */
} ProcCmdlineFlags;
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
#endif
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "io-util.h"
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
for (;;) {
- r = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK);
+ r = getrandom(p, n,
+ (FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
+ (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
if (r > 0) {
have_syscall = true;
have_syscall = true;
return -EIO;
- } else if (errno == ENOSYS) {
+ } else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
/* We lack the syscall, continue with reading from /dev/urandom. */
have_syscall = false;
break;
/* Use /dev/urandom instead */
break;
+
+ } else if (errno == EINVAL) {
+
+ /* Most likely: unknown flag. We know that GRND_INSECURE might cause this,
+ * hence try without. */
+
+ if (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE)) {
+ flags = flags &~ RANDOM_ALLOW_INSECURE;
+ continue;
+ }
+
+ return -errno;
} else
return -errno;
}
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
#if RAND_MAX >= INT_MAX
+assert_cc(RAND_MAX >= 16777215);
# define RAND_STEP 3
#else
-/* SHORT_INT_MAX or lower gives at most 15 bits, we just just 8 out of that. */
+/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
+assert_cc(RAND_MAX >= 255);
# define RAND_STEP 1
#endif
* This function is hence not useful for generating UUIDs or cryptographic key material.
*/
- if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND) >= 0)
+ if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND|RANDOM_ALLOW_INSECURE) >= 0)
return;
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
RANDOM_BLOCK = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
RANDOM_MAY_FAIL = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */
RANDOM_ALLOW_RDRAND = 1 << 3, /* Allow usage of the CPU RNG */
+ RANDOM_ALLOW_INSECURE = 1 << 4, /* Allow usage of GRND_INSECURE flag to kernel's getrandom() API */
} RandomFlags;
int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
}
int set_consume(Set *s, void *value);
-int set_put_strdup(Set *s, const char *p);
-int set_put_strdupv(Set *s, char **l);
+int set_put_strdup(Set **s, const char *p);
+int set_put_strdupv(Set **s, char **l);
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
#define SET_FOREACH(e, s, i) \
const struct sockaddr *sa, socklen_t len,
int flags) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control = {};
struct msghdr mh = {
.msg_name = (struct sockaddr*) sa,
.msg_namelen = len,
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = CMSG_SPACE(sizeof(int));
}
k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags);
if (k < 0)
int flags,
int *ret_fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
struct msghdr mh = {
.msg_control = &control,
.msg_controllen = sizeof(control),
.msg_iov = iov,
.msg_iovlen = iovlen,
};
- struct cmsghdr *cmsg, *found = NULL;
+ struct cmsghdr *found;
ssize_t k;
assert(transport_fd >= 0);
* combination with send_one_fd().
*/
- k = recvmsg(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
+ k = recvmsg_safe(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
if (k < 0)
- return (ssize_t) -errno;
+ return k;
- CMSG_FOREACH(cmsg, &mh) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
- assert(!found);
- found = cmsg;
- break;
- }
- }
-
- if (!found)
+ found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
+ if (!found) {
cmsg_close_all(&mh);
- /* If didn't receive an FD or any data, return an error. */
- if (k == 0 && !found)
- return -EIO;
+ /* If didn't receive an FD or any data, return an error. */
+ if (k == 0)
+ return -EIO;
+ }
if (found)
*ret_fd = *(int*) CMSG_DATA(found);
return socket_bind_to_ifname(fd, ifname);
}
+
+ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) {
+ ssize_t n;
+
+ /* A wrapper around recvmsg() that checks for MSG_CTRUNC, and turns it into an error, in a reasonably
+ * safe way, closing any SCM_RIGHTS fds in the error path.
+ *
+ * Note that unlike our usual coding style this might modify *msg on failure. */
+
+ n = recvmsg(sockfd, msg, flags);
+ if (n < 0)
+ return -errno;
+
+ if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) {
+ cmsg_close_all(msg);
+ return -EXFULL; /* a recognizable error code */
+ }
+
+ return n;
+
+}
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+/* Type-safe, dereferencing version of cmsg_find() */
+#define CMSG_FIND_DATA(mh, level, type, ctype) \
+ ({ \
+ struct cmsghdr *_found; \
+ _found = cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))); \
+ (ctype*) (_found ? CMSG_DATA(_found) : NULL); \
+ })
+
+/* Resolves to a type that can carry cmsghdr structures. Make sure things are properly aligned, i.e. the type
+ * itself is placed properly in memory and the size is also aligned to what's appropriate for "cmsghdr"
+ * structures. */
+#define CMSG_BUFFER_TYPE(size) \
+ union { \
+ struct cmsghdr cmsghdr; \
+ uint8_t buf[size]; \
+ uint8_t align_check[(size) >= CMSG_SPACE(0) && \
+ (size) == CMSG_ALIGN(size) ? 1 : -1]; \
+ }
+
/*
* Certain hardware address types (e.g Infiniband) do not fit into sll_addr
* (8 bytes) and run over the structure. This macro returns the correct size that
int socket_bind_to_ifname(int fd, const char *ifname);
int socket_bind_to_ifindex(int fd, int ifindex);
+
+ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags);
}
int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
- _cleanup_close_ int fd = -1;
+ struct statfs s;
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
- if (fd < 0)
+ if (statfs(path, &s) < 0)
return -errno;
- return fd_is_fs_type(fd, magic_value);
+ return is_fs_type(&s, magic_value);
}
bool is_temporary_fs(const struct statfs *s) {
return 0;
}
+
+int proc_mounted(void) {
+ int r;
+
+ /* A quick check of procfs is properly mounted */
+
+ r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
+ if (r == -ENOENT) /* not mounted at all */
+ return false;
+
+ return r;
+}
+
+bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
+
+ /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
+ * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
+ * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
+ * size, backing device, inode type and if this refers to a device not the major/minor.
+ *
+ * Note that we don't care if file attributes such as ownership or access mode change, this here is
+ * about contents of the file. The purpose here is to detect file contents changes, and nothing
+ * else. */
+
+ return a && b &&
+ (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
+ ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
+ a->st_mtime == b->st_mtime &&
+ (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
+ a->st_dev == b->st_dev &&
+ a->st_ino == b->st_ino &&
+ (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
+}
int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
+
+int proc_mounted(void);
+
+bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
return NULL;
}
+char *strv_find_case(char * const *l, const char *name) {
+ char * const *i;
+
+ assert(name);
+
+ STRV_FOREACH(i, l)
+ if (strcaseeq(*i, name))
+ return *i;
+
+ return NULL;
+}
+
char *strv_find_prefix(char * const *l, const char *name) {
char * const *i;
#include "string-util.h"
char *strv_find(char * const *l, const char *name) _pure_;
+char *strv_find_case(char * const *l, const char *name) _pure_;
char *strv_find_prefix(char * const *l, const char *name) _pure_;
char *strv_find_startswith(char * const *l, const char *name) _pure_;
+#define strv_contains(l, s) (!!strv_find((l), (s)))
+#define strv_contains_case(l, s) (!!strv_find_case((l), (s)))
+
char **strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)
return strv_compare(a, b) == 0;
}
-#define strv_contains(l, s) (!!strv_find((l), (s)))
-
char **strv_new_internal(const char *x, ...) _sentinel_;
char **strv_new_ap(const char *x, va_list ap);
#define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
#define STRV_FOREACH_BACKWARDS(s, l) \
for (s = ({ \
- char **_l = l; \
+ typeof(l) _l = l; \
_l ? _l + strv_length(_l) - 1U : NULL; \
}); \
(l) && ((s) >= (l)); \
(s)--)
#define STRV_FOREACH_PAIR(x, y, l) \
- for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
+ for ((x) = (l), (y) = (x) ? (x+1) : NULL; (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
char **strv_sort(char **l);
void strv_print(char * const *l);
_x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
})
+#define STRCASE_IN_SET(x, ...) strv_contains_case(STRV_MAKE(__VA_ARGS__), x)
+#define STRCASEPTR_IN_SET(x, ...) \
+ ({ \
+ const char* _x = (x); \
+ _x && strv_contains_case(STRV_MAKE(__VA_ARGS__), _x); \
+ })
+
#define STARTSWITH_SET(p, ...) \
({ \
const char *_p = (p); \
#define ANSI_HIGHLIGHT_YELLOW4 "\x1B[0;1;38;5;100m"
/* Underlined */
+#define ANSI_GREY_UNDERLINE "\x1B[0;4;38;5;245m"
#define ANSI_HIGHLIGHT_RED_UNDERLINE "\x1B[0;1;4;31m"
#define ANSI_HIGHLIGHT_GREEN_UNDERLINE "\x1B[0;1;4;32m"
#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;38;5;185m"
DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT_UNDERLINE, HIGHLIGHT);
+DEFINE_ANSI_FUNC_UNDERLINE(grey_underline, GREY_UNDERLINE, GREY);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW);
DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
+static const char* const freezer_state_table[_FREEZER_STATE_MAX] = {
+ [FREEZER_RUNNING] = "running",
+ [FREEZER_FREEZING] = "freezing",
+ [FREEZER_FROZEN] = "frozen",
+ [FREEZER_THAWING] = "thawing",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(freezer_state, FreezerState);
+
static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
[AUTOMOUNT_DEAD] = "dead",
[AUTOMOUNT_WAITING] = "waiting",
_UNIT_ACTIVE_STATE_INVALID = -1
} UnitActiveState;
+typedef enum FreezerState {
+ FREEZER_RUNNING,
+ FREEZER_FREEZING,
+ FREEZER_FROZEN,
+ FREEZER_THAWING,
+ _FREEZER_STATE_MAX,
+ _FREEZER_STATE_INVALID = -1
+} FreezerState;
+
typedef enum AutomountState {
AUTOMOUNT_DEAD,
AUTOMOUNT_WAITING,
const char *unit_active_state_to_string(UnitActiveState i) _const_;
UnitActiveState unit_active_state_from_string(const char *s) _pure_;
+const char *freezer_state_to_string(FreezerState i) _const_;
+FreezerState freezer_state_from_string(const char *s) _pure_;
+
const char* automount_state_to_string(AutomountState i) _const_;
AutomountState automount_state_from_string(const char *s) _pure_;
goto finish;
}
- /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364,
- * ... and a working one, since the official one doesn't actually work ;(
- */
+ /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 */
r = read_one_line_file("/proc/sys/kernel/osrelease", &o);
if (r >= 0 &&
- (strstr(o, "Microsoft") || strstr(o, "microsoft") || strstr(o, "WSL"))) {
+ (strstr(o, "Microsoft") || strstr(o, "WSL"))) {
r = VIRTUALIZATION_WSL;
goto finish;
}
#include <sys/types.h>
#include "alloc-util.h"
+#include "binfmt-util.h"
#include "conf-files.h"
#include "def.h"
#include "fd-util.h"
static bool arg_cat_config = false;
static PagerFlags arg_pager_flags = 0;
+static bool arg_unregister = false;
static int delete_rule(const char *rule) {
_cleanup_free_ char *x = NULL, *fn = NULL;
assert(rule);
assert(rule[0]);
- x = strdup(rule);
+ e = strchrnul(rule + 1, rule[0]);
+ x = strndup(rule + 1, e - rule - 1);
if (!x)
return log_oom();
- e = strchrnul(x+1, x[0]);
- *e = 0;
-
- if (!filename_is_valid(x + 1))
+ if (!filename_is_valid(x) ||
+ STR_IN_SET(x, "register", "status"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Rule file name '%s' is not valid, refusing.", x + 1);
+ "Rule file name '%s' is not valid, refusing.", x);
- fn = path_join("/proc/sys/fs/binfmt_misc", x+1);
+ fn = path_join("/proc/sys/fs/binfmt_misc", x);
if (!fn)
return log_oom();
" --version Show package version\n"
" --cat-config Show configuration files\n"
" --no-pager Do not pipe output into a pager\n"
+ " --unregister Unregister all existing entries\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, link
ARG_VERSION = 0x100,
ARG_CAT_CONFIG,
ARG_NO_PAGER,
+ ARG_UNREGISTER,
};
static const struct option options[] = {
{ "version", no_argument, NULL, ARG_VERSION },
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "unregister", no_argument, NULL, ARG_UNREGISTER },
{}
};
arg_pager_flags |= PAGER_DISABLE;
break;
+ case ARG_UNREGISTER:
+ arg_unregister = true;
+ break;
+
case '?':
return -EINVAL;
assert_not_reached("Unhandled option");
}
- if (arg_cat_config && argc > optind)
+ if ((arg_unregister || arg_cat_config) && argc > optind)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Positional arguments are not allowed with --cat-config");
+ "Positional arguments are not allowed with --cat-config or --unregister");
return 1;
}
r = 0;
+ if (arg_unregister)
+ return disable_binfmt();
+
if (argc > optind) {
int i;
if (!force) {
fd_to = open(to, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd_to < 0) {
- if (errno != -ENOENT)
+ if (errno != ENOENT)
return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
} else {
r = version_check(fd_from, from, fd_to, to);
assert(paths);
- r = set_put_strdup(paths, path);
+ r = set_put_strdup(&paths, path);
if (r < 0)
return log_oom();
assert(interface);
assert(members);
- m = new0(Member, 1);
+ m = new(Member, 1);
if (!m)
return log_oom();
- m->type = "interface";
- m->flags = flags;
+ *m = (Member) {
+ .type = "interface",
+ .flags = flags,
+ };
r = free_and_strdup(&m->interface, interface);
if (r < 0)
return log_oom();
r = set_put(members, m);
- if (r <= 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate interface");
+ if (r == -EEXIST)
+ return log_error_errno(r, "Invalid introspection data: duplicate interface '%s'.", interface);
+ if (r < 0)
+ return log_oom();
m = NULL;
return 0;
assert(interface);
assert(name);
- m = new0(Member, 1);
+ m = new(Member, 1);
if (!m)
return log_oom();
- m->type = "method";
- m->flags = flags;
+ *m = (Member) {
+ .type = "method",
+ .flags = flags,
+ };
r = free_and_strdup(&m->interface, interface);
if (r < 0)
return log_oom();
r = set_put(members, m);
- if (r <= 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate method");
+ if (r == -EEXIST)
+ return log_error_errno(r, "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
+ if (r < 0)
+ return log_oom();
m = NULL;
return 0;
assert(interface);
assert(name);
- m = new0(Member, 1);
+ m = new(Member, 1);
if (!m)
return log_oom();
- m->type = "signal";
- m->flags = flags;
+ *m = (Member) {
+ .type = "signal",
+ .flags = flags,
+ };
r = free_and_strdup(&m->interface, interface);
if (r < 0)
return log_oom();
r = set_put(members, m);
- if (r <= 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate signal");
+ if (r == -EEXIST)
+ return log_error_errno(r, "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
+ if (r < 0)
+ return log_oom();
m = NULL;
return 0;
assert(interface);
assert(name);
- m = new0(Member, 1);
+ m = new(Member, 1);
if (!m)
return log_oom();
- m->type = "property";
- m->flags = flags;
- m->writable = writable;
+ *m = (Member) {
+ .type = "property",
+ .flags = flags,
+ .writable = writable,
+ };
r = free_and_strdup(&m->interface, interface);
if (r < 0)
return log_oom();
r = set_put(members, m);
- if (r <= 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate property");
+ if (r == -EEXIST)
+ return log_error_errno(r, "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
+ if (r < 0)
+ return log_oom();
m = NULL;
return 0;
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
+ r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_LOCAL_FS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
+ if (r < 0)
+ return r;
+
r = unit_add_dependency_by_name(UNIT(a), UNIT_AFTER, SPECIAL_LOCAL_FS_PRE_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
.reset_failed = automount_reset_failed,
- .bus_vtable = bus_automount_vtable,
.bus_set_property = bus_automount_set_property,
.shutdown = automount_shutdown,
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "io-util.h"
#include "limits-util.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
log_debug_errno(r, "Failed to enable cgroup empty event source: %m");
}
+static void unit_remove_from_cgroup_empty_queue(Unit *u) {
+ assert(u);
+
+ if (!u->in_cgroup_empty_queue)
+ return;
+
+ LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
+ u->in_cgroup_empty_queue = false;
+}
+
int unit_check_oom(Unit *u) {
_cleanup_free_ char *oom_kill = NULL;
bool increased;
log_error_errno(r, "Failed to enable cgroup oom event source: %m");
}
+static int unit_check_cgroup_events(Unit *u) {
+ char *values[2] = {};
+ int r;
+
+ assert(u);
+
+ r = cg_get_keyed_attribute_graceful(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events",
+ STRV_MAKE("populated", "frozen"), values);
+ if (r < 0)
+ return r;
+
+ /* The cgroup.events notifications can be merged together so act as we saw the given state for the
+ * first time. The functions we call to handle given state are idempotent, which makes them
+ * effectively remember the previous state. */
+ if (values[0]) {
+ if (streq(values[0], "1"))
+ unit_remove_from_cgroup_empty_queue(u);
+ else
+ unit_add_to_cgroup_empty_queue(u);
+ }
+
+ /* Disregard freezer state changes due to operations not initiated by us */
+ if (values[1] && IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING)) {
+ if (streq(values[1], "0"))
+ unit_thawed(u);
+ else
+ unit_frozen(u);
+ }
+
+ free(values[0]);
+ free(values[1]);
+
+ return 0;
+}
+
static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
u = hashmap_get(m->cgroup_control_inotify_wd_unit, INT_TO_PTR(e->wd));
if (u)
- unit_add_to_cgroup_empty_queue(u);
+ unit_check_cgroup_events(u);
u = hashmap_get(m->cgroup_memory_inotify_wd_unit, INT_TO_PTR(e->wd));
if (u)
return strcmp(x->unit->id, y->unit->id);
}
+int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
+ _cleanup_free_ char *path = NULL;
+ FreezerState target, kernel = _FREEZER_STATE_INVALID;
+ int r;
+
+ assert(u);
+ assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+ if (!u->cgroup_realized)
+ return -EBUSY;
+
+ target = action == FREEZER_FREEZE ? FREEZER_FROZEN : FREEZER_RUNNING;
+
+ r = unit_freezer_state_kernel(u, &kernel);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to obtain cgroup freezer state: %m");
+
+ if (target == kernel) {
+ u->freezer_state = target;
+ return 0;
+ }
+
+ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.freeze", &path);
+ if (r < 0)
+ return r;
+
+ log_unit_debug(u, "%s unit.", action == FREEZER_FREEZE ? "Freezing" : "Thawing");
+
+ if (action == FREEZER_FREEZE)
+ u->freezer_state = FREEZER_FREEZING;
+ else
+ u->freezer_state = FREEZER_THAWING;
+
+ r = write_string_file(path, one_zero(action == FREEZER_FREEZE), WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
[CGROUP_DEVICE_POLICY_AUTO] = "auto",
[CGROUP_DEVICE_POLICY_CLOSED] = "closed",
}
DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);
+
+static const char* const freezer_action_table[_FREEZER_ACTION_MAX] = {
+ [FREEZER_FREEZE] = "freeze",
+ [FREEZER_THAW] = "thaw",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(freezer_action, FreezerAction);
_CGROUP_DEVICE_POLICY_INVALID = -1
} CGroupDevicePolicy;
+typedef enum FreezerAction {
+ FREEZER_FREEZE,
+ FREEZER_THAW,
+
+ _FREEZER_ACTION_MAX,
+ _FREEZER_ACTION_INVALID = -1,
+} FreezerAction;
+
struct CGroupDeviceAllow {
LIST_FIELDS(CGroupDeviceAllow, device_allow);
char *path;
int compare_job_priority(const void *a, const void *b);
int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name);
+int unit_cgroup_freezer_action(Unit *u, FreezerAction action);
+
+const char* freezer_action_to_string(FreezerAction a) _const_;
+FreezerAction freezer_action_from_string(const char *s) _pure_;
if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m");
- (void) mkdir_p("/run/systemd/userdb", 0755);
+ if (!MANAGER_IS_TEST_RUN(m)) {
+ (void) mkdir_p("/run/systemd/userdb", 0755);
- r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666);
- if (r < 0)
- return log_error_errno(r, "Failed to bind to varlink socket: %m");
+ r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind to varlink socket: %m");
+ }
r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
SD_BUS_VTABLE_END
};
+static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+ Manager *m = userdata;
+ Job *j;
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(interface);
+ assert(found);
+ assert(m);
+
+ r = manager_get_job_from_dbus_path(m, path, &j);
+ if (r < 0)
+ return 0;
+
+ *found = j;
+ return 1;
+}
+
+static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+ _cleanup_strv_free_ char **l = NULL;
+ Manager *m = userdata;
+ unsigned k = 0;
+ Iterator i;
+ Job *j;
+
+ l = new0(char*, hashmap_size(m->jobs)+1);
+ if (!l)
+ return -ENOMEM;
+
+ HASHMAP_FOREACH(j, m->jobs, i) {
+ l[k] = job_dbus_path(j);
+ if (!l[k])
+ return -ENOMEM;
+
+ k++;
+ }
+
+ assert(hashmap_size(m->jobs) == k);
+
+ *nodes = TAKE_PTR(l);
+
+ return k;
+}
+
+const BusObjectImplementation job_object = {
+ "/org/freedesktop/systemd1/job",
+ "org.freedesktop.systemd1.Job",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({bus_job_vtable, bus_job_find}),
+ .node_enumerator = bus_job_enumerate,
+};
+
static int send_new_signal(sd_bus *bus, void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ char *p = NULL;
#pragma once
#include "sd-bus.h"
-#include "sd-bus-vtable.h"
#include "unit.h"
+#include "bus-util.h"
extern const sd_bus_vtable bus_job_vtable[];
+extern const BusObjectImplementation job_object;
int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error);
int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error);
return sd_bus_message_append_basic(reply, 'b', &b);
}
-static int property_set_runtime_watchdog(
+static int property_get_runtime_watchdog(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
- sd_bus_message *value,
+ sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
- usec_t *t = userdata;
- int r;
+ Manager *m = userdata;
+
+ assert(m);
+ assert(bus);
+ assert(reply);
+
+ return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_RUNTIME));
+}
+
+static int property_get_reboot_watchdog(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ assert(m);
assert(bus);
+ assert(reply);
+
+ return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_REBOOT));
+}
+
+static int property_get_kexec_watchdog(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(m);
+ assert(bus);
+ assert(reply);
+
+ return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_KEXEC));
+}
+
+static int property_set_watchdog(Manager *m, WatchdogType type, sd_bus_message *value) {
+ usec_t timeout;
+ int r;
+
+ assert(m);
assert(value);
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
- r = sd_bus_message_read(value, "t", t);
+ r = sd_bus_message_read(value, "t", &timeout);
if (r < 0)
return r;
- return watchdog_set_timeout(t);
+ return manager_set_watchdog_overridden(m, type, timeout);
+}
+
+static int property_set_runtime_watchdog(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *value,
+ void *userdata,
+ sd_bus_error *error) {
+
+ return property_set_watchdog(userdata, WATCHDOG_RUNTIME, value);
+}
+
+static int property_set_reboot_watchdog(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *value,
+ void *userdata,
+ sd_bus_error *error) {
+
+ return property_set_watchdog(userdata, WATCHDOG_REBOOT, value);
+}
+
+static int property_set_kexec_watchdog(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *value,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(m);
+ assert(bus);
+ assert(value);
+
+ return property_set_watchdog(userdata, WATCHDOG_KEXEC, value);
}
static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
return method_generic_unit_operation(message, userdata, error, bus_unit_method_clean, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED);
}
+static int method_freeze_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_generic_unit_operation(message, userdata, error, bus_unit_method_freeze, 0);
+}
+
+static int method_thaw_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_generic_unit_operation(message, userdata, error, bus_unit_method_thaw, 0);
+}
+
static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
/* Don't load the unit (because unloaded units can't be in failed state), and don't insist on the
* unit to be loaded properly (since a failed unit might have its unit file disappeared) */
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
- SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), 0),
+ SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", property_get_runtime_watchdog, property_set_runtime_watchdog, 0, 0),
+ SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, 0),
/* The following item is an obsolete alias */
- SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), SD_BUS_VTABLE_HIDDEN),
- SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, kexec_watchdog), 0),
+ SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", property_get_kexec_watchdog, property_set_kexec_watchdog, 0, 0),
SD_BUS_WRITABLE_PROPERTY("ServiceWatchdogs", "b", bus_property_get_bool, bus_property_set_bool, offsetof(Manager, service_watchdogs), 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
NULL,,
method_clean_unit,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("FreezeUnit",
+ "s",
+ SD_BUS_PARAM(name),
+ NULL,,
+ method_freeze_unit,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("ThawUnit",
+ "s",
+ SD_BUS_PARAM(name),
+ NULL,,
+ method_thaw_unit,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("ResetFailedUnit",
"s",
SD_BUS_PARAM(name),
SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LazyUnmount", "b", bus_property_get_bool, offsetof(Mount, lazy_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ReadWriteOnly", "b", bus_property_get_bool, offsetof(Mount, read_write_only), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
if (streq(name, "ForceUnmount"))
return bus_set_transient_bool(u, name, &m->force_unmount, message, flags, error);
+ if (streq(name, "ReadWriteOnly"))
+ return bus_set_transient_bool(u, name, &m->read_write_only, message, flags, error);
+
return 0;
}
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
static BUS_DEFINE_PROPERTY_GET(property_get_description, "s", Unit, unit_description);
static BUS_DEFINE_PROPERTY_GET2(property_get_active_state, "s", Unit, unit_active_state, unit_active_state_to_string);
+static BUS_DEFINE_PROPERTY_GET2(property_get_freezer_state, "s", Unit, unit_freezer_state, freezer_state_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_sub_state, "s", Unit, unit_sub_state_to_string);
static BUS_DEFINE_PROPERTY_GET2(property_get_unit_file_state, "s", Unit, unit_get_unit_file_state, unit_file_state_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_can_reload, "b", Unit, unit_can_reload);
static BUS_DEFINE_PROPERTY_GET(property_get_can_start, "b", Unit, unit_can_start_refuse_manual);
static BUS_DEFINE_PROPERTY_GET(property_get_can_stop, "b", Unit, unit_can_stop_refuse_manual);
static BUS_DEFINE_PROPERTY_GET(property_get_can_isolate, "b", Unit, unit_can_isolate_refuse_manual);
+static BUS_DEFINE_PROPERTY_GET(property_get_can_freeze, "b", Unit, unit_can_freeze);
static BUS_DEFINE_PROPERTY_GET(property_get_need_daemon_reload, "b", Unit, unit_need_daemon_reload);
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_strv, "as", 0);
return sd_bus_reply_method_return(message, NULL);
}
+static int bus_unit_method_freezer_generic(sd_bus_message *message, void *userdata, sd_bus_error *error, FreezerAction action) {
+ const char* perm;
+ int (*method)(Unit*);
+ Unit *u = userdata;
+ bool reply_no_delay = false;
+ int r;
+
+ assert(message);
+ assert(u);
+ assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+ if (action == FREEZER_FREEZE) {
+ perm = "stop";
+ method = unit_freeze;
+ } else {
+ perm = "start";
+ method = unit_thaw;
+ }
+
+ r = mac_selinux_unit_access_check(u, message, perm, error);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_manage_units_async_full(
+ u,
+ perm,
+ CAP_SYS_ADMIN,
+ N_("Authentication is required to freeze or thaw the processes of '$(unit)' unit."),
+ true,
+ message,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ r = method(u);
+ if (r == -EOPNOTSUPP)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Unit '%s' does not support freezing.", u->id);
+ if (r == -EBUSY)
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_BUSY, "Unit has a pending job.");
+ if (r == -EHOSTDOWN)
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_INACTIVE, "Unit is inactive.");
+ if (r == -EALREADY)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Previously requested freezer operation for unit '%s' is still in progress.", u->id);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ reply_no_delay = true;
+
+ assert(!u->pending_freezer_message);
+
+ r = sd_bus_message_new_method_return(message, &u->pending_freezer_message);
+ if (r < 0)
+ return r;
+
+ if (reply_no_delay) {
+ r = bus_unit_send_pending_freezer_message(u);
+ if (r < 0)
+ return r;
+ }
+
+ return 1;
+}
+
+int bus_unit_method_thaw(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_freezer_generic(message, userdata, error, FREEZER_THAW);
+}
+
+int bus_unit_method_freeze(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_freezer_generic(message, userdata, error, FREEZER_FREEZE);
+}
+
static int property_get_refs(
sd_bus *bus,
const char *path,
SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("FreezerState", "s", property_get_freezer_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanClean", "as", property_get_can_clean, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("CanFreeze", "b", property_get_can_freeze, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Job", "(uo)", property_get_job, offsetof(Unit, job), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST),
NULL,,
bus_unit_method_clean,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Freeze",
+ NULL,
+ NULL,
+ bus_unit_method_freeze,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Thaw",
+ NULL,
+ NULL,
+ bus_unit_method_thaw,
+ SD_BUS_VTABLE_UNPRIVILEGED),
/* For dependency types we don't support anymore always return an empty array */
SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_empty_strv, 0, SD_BUS_VTABLE_HIDDEN),
bus_unit_send_change_signal(u);
}
+int bus_unit_send_pending_freezer_message(Unit *u) {
+ int r;
+
+ assert(u);
+
+ if (!u->pending_freezer_message)
+ return 0;
+
+ r = sd_bus_send(NULL, u->pending_freezer_message, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to send queued message, ignoring: %m");
+
+ u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
+
+ return 0;
+}
+
static int send_removed_signal(sd_bus *bus, void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ char *p = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *job_path = NULL, *unit_path = NULL;
- _cleanup_(set_freep) Set *affected = NULL;
+ _cleanup_set_free_ Set *affected = NULL;
Iterator i;
Job *j, *a;
int r;
#pragma once
#include "sd-bus.h"
-#include "sd-bus-vtable.h"
#include "unit.h"
void bus_unit_send_change_signal(Unit *u);
void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
+int bus_unit_send_pending_freezer_message(Unit *u);
void bus_unit_send_removed_signal(Unit *u);
int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_clean(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_freeze(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_thaw(sd_bus_message *message, void *userdata, sd_bus_error *error);
typedef enum BusUnitQueueFlags {
BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE = 1 << 0,
}
#endif
-static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- Job *j;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = manager_get_job_from_dbus_path(m, path, &j);
- if (r < 0)
- return 0;
-
- *found = j;
- return 1;
-}
-
static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
Unit *u = NULL; /* just to appease gcc, initialization is not really necessary */
int r;
return 1;
}
-static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
- _cleanup_strv_free_ char **l = NULL;
- Manager *m = userdata;
- unsigned k = 0;
- Iterator i;
- Job *j;
-
- l = new0(char*, hashmap_size(m->jobs)+1);
- if (!l)
- return -ENOMEM;
-
- HASHMAP_FOREACH(j, m->jobs, i) {
- l[k] = job_dbus_path(j);
- if (!l[k])
- return -ENOMEM;
-
- k++;
- }
-
- assert(hashmap_size(m->jobs) == k);
-
- *nodes = TAKE_PTR(l);
-
- return k;
-}
-
static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
return k;
}
+static const BusObjectImplementation unit_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Unit",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_unit_vtable, bus_unit_find }),
+ .node_enumerator = bus_unit_enumerate,
+};
+
+static const BusObjectImplementation bus_automount_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Automount",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_automount_vtable, bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_device_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Device",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_device_vtable, bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_mount_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Mount",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_mount_vtable, bus_unit_interface_find },
+ { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+ { bus_cgroup_vtable, bus_cgroup_context_find },
+ { bus_exec_vtable, bus_exec_context_find },
+ { bus_kill_vtable, bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_path_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Path",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_path_vtable, bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_scope_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Scope",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_scope_vtable, bus_unit_interface_find },
+ { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+ { bus_cgroup_vtable, bus_cgroup_context_find },
+ { bus_kill_vtable, bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_service_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Service",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_service_vtable, bus_unit_interface_find },
+ { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+ { bus_cgroup_vtable, bus_cgroup_context_find },
+ { bus_exec_vtable, bus_exec_context_find },
+ { bus_kill_vtable, bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_slice_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Slice",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_slice_vtable, bus_unit_interface_find },
+ { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+ { bus_cgroup_vtable, bus_cgroup_context_find }),
+};
+
+static const BusObjectImplementation bus_socket_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Socket",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_socket_vtable, bus_unit_interface_find },
+ { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+ { bus_cgroup_vtable, bus_cgroup_context_find },
+ { bus_exec_vtable, bus_exec_context_find },
+ { bus_kill_vtable, bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_swap_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Swap",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_swap_vtable, bus_unit_interface_find },
+ { bus_unit_cgroup_vtable, bus_unit_cgroup_find },
+ { bus_cgroup_vtable, bus_cgroup_context_find },
+ { bus_exec_vtable, bus_exec_context_find },
+ { bus_kill_vtable, bus_kill_context_find }),
+};
+
+static const BusObjectImplementation bus_target_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Target",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_target_vtable, bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_timer_object = {
+ "/org/freedesktop/systemd1/unit",
+ "org.freedesktop.systemd1.Timer",
+ .fallback_vtables = BUS_FALLBACK_VTABLES(
+ { bus_timer_vtable, bus_unit_interface_find }),
+};
+
+static const BusObjectImplementation bus_manager_object = {
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ .vtables = BUS_VTABLES(bus_manager_vtable),
+ .children = BUS_IMPLEMENTATIONS(
+ &job_object,
+ &unit_object,
+ &bus_automount_object,
+ &bus_device_object,
+ &bus_mount_object,
+ &bus_path_object,
+ &bus_scope_object,
+ &bus_service_object,
+ &bus_slice_object,
+ &bus_socket_object,
+ &bus_swap_object,
+ &bus_target_object,
+ &bus_timer_object),
+};
+
+static const BusObjectImplementation manager_log_control_object = {
+ "/org/freedesktop/LogControl1",
+ "org.freedesktop.LogControl1",
+ .vtables = BUS_VTABLES(bus_manager_log_control_vtable),
+};
+
+int bus_manager_introspect_implementations(FILE *out, const char *pattern) {
+ return bus_introspect_implementations(
+ out,
+ pattern,
+ BUS_IMPLEMENTATIONS(&bus_manager_object,
+ &manager_log_control_object));
+}
+
static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
- UnitType t;
int r;
assert(m);
return log_error_errno(r, "Failed to add SELinux access filter: %m");
#endif
- r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register Manager vtable: %m");
-
- r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/LogControl1", "org.freedesktop.LogControl1", bus_manager_log_control_vtable, m);
+ r = bus_add_implementation(bus, &bus_manager_object, m);
if (r < 0)
- return log_error_errno(r, "Failed to register service API vtable: %m");
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register Job vtable: %m");
-
- r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add job enumerator: %m");
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register Unit vtable: %m");
-
- r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add job enumerator: %m");
-
- for (t = 0; t < _UNIT_TYPE_MAX; t++) {
- const char *interface;
-
- assert_se(interface = unit_dbus_interface_from_type(t));
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register type specific vtable for %s: %m", interface);
-
- if (unit_vtable[t]->cgroup_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", interface);
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register control group vtable for %s: %m", interface);
- }
-
- if (unit_vtable[t]->exec_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_exec_vtable, bus_exec_context_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register execute vtable for %s: %m", interface);
- }
-
- if (unit_vtable[t]->kill_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_kill_vtable, bus_kill_context_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register kill vtable for %s: %m", interface);
- }
- }
+ return r;
- return 0;
+ return bus_add_implementation(bus, &manager_log_control_object, m);
}
static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
if (j->bus_track && sd_bus_track_get_bus(j->bus_track) == *bus)
j->bus_track = sd_bus_track_unref(j->bus_track);
- HASHMAP_FOREACH(u, m->units, i)
+ HASHMAP_FOREACH(u, m->units, i) {
if (u->bus_track && sd_bus_track_get_bus(u->bus_track) == *bus)
u->bus_track = sd_bus_track_unref(u->bus_track);
+ /* Get rid of pending freezer messages on this bus */
+ if (u->pending_freezer_message && sd_bus_message_get_bus(u->pending_freezer_message) == *bus)
+ u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
+ }
+
/* Get rid of queued message on this bus */
if (m->pending_reload_message && sd_bus_message_get_bus(m->pending_reload_message) == *bus)
m->pending_reload_message = sd_bus_message_unref(m->pending_reload_message);
uint64_t manager_bus_n_queued_write(Manager *m);
void dump_bus_properties(FILE *f);
+int bus_manager_introspect_implementations(FILE *out, const char *pattern);
"Device\0"
"Install\0",
- .refuse_after = true,
.gc_jobs = true,
.init = device_init,
.active_state = device_active_state,
.sub_state_to_string = device_sub_state_to_string,
- .bus_vtable = bus_device_vtable,
-
.following = device_following,
.following_set = device_following_set,
static bool is_terminal_output(ExecOutput o) {
return IN_SET(o,
EXEC_OUTPUT_TTY,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
EXEC_OUTPUT_KMSG_AND_CONSOLE,
EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
}
-static bool is_syslog_output(ExecOutput o) {
- return IN_SET(o,
- EXEC_OUTPUT_SYSLOG,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE);
-}
-
static bool is_kmsg_output(ExecOutput o) {
return IN_SET(o,
EXEC_OUTPUT_KMSG,
params->flags & EXEC_PASS_LOG_UNIT ? unit->id : "",
context->syslog_priority,
!!context->syslog_level_prefix,
- is_syslog_output(output),
+ false,
is_kmsg_output(output),
is_terminal_output(output)) < 0)
return -errno;
/* We don't reset the terminal if this is just about output */
return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno);
- case EXEC_OUTPUT_SYSLOG:
- case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
#endif
static int apply_protect_hostname(const Unit *u, const ExecContext *c, int *ret_exit_status) {
- int r;
-
assert(u);
assert(c);
log_unit_warning(u, "ProtectHostname=yes is configured, but the kernel does not support UTS namespaces, ignoring namespace setup.");
#if HAVE_SECCOMP
+ int r;
+
if (skip_seccomp_unavailable(u, "ProtectHostname="))
return 0;
prefix, yes_no(c->tty_vt_disallocate));
if (IN_SET(c->std_output,
- EXEC_OUTPUT_SYSLOG,
EXEC_OUTPUT_KMSG,
EXEC_OUTPUT_JOURNAL,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
EXEC_OUTPUT_KMSG_AND_CONSOLE,
EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
IN_SET(c->std_error,
- EXEC_OUTPUT_SYSLOG,
EXEC_OUTPUT_KMSG,
EXEC_OUTPUT_JOURNAL,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
EXEC_OUTPUT_KMSG_AND_CONSOLE,
EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
[EXEC_OUTPUT_INHERIT] = "inherit",
[EXEC_OUTPUT_NULL] = "null",
[EXEC_OUTPUT_TTY] = "tty",
- [EXEC_OUTPUT_SYSLOG] = "syslog",
- [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
[EXEC_OUTPUT_KMSG] = "kmsg",
[EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
[EXEC_OUTPUT_JOURNAL] = "journal",
EXEC_OUTPUT_INHERIT,
EXEC_OUTPUT_NULL,
EXEC_OUTPUT_TTY,
- EXEC_OUTPUT_SYSLOG,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
EXEC_OUTPUT_KMSG,
EXEC_OUTPUT_KMSG_AND_CONSOLE,
EXEC_OUTPUT_JOURNAL,
#include "hostname-util.h"
#include "log.h"
#include "macro.h"
+#include "proc-cmdline.h"
#include "string-util.h"
#include "util.h"
int hostname_setup(void) {
_cleanup_free_ char *b = NULL;
+ const char *hn = NULL;
bool enoent = false;
- const char *hn;
int r;
- r = read_etc_hostname(NULL, &b);
- if (r < 0) {
- if (r == -ENOENT)
- enoent = true;
- else
- log_warning_errno(r, "Failed to read configured hostname: %m");
+ r = proc_cmdline_get_key("systemd.hostname", 0, &b);
+ if (r < 0)
+ log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
+ else if (r > 0) {
+ if (hostname_is_valid(b, true))
+ hn = b;
+ else {
+ log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
+ b = mfree(b);
+ }
+ }
- hn = NULL;
- } else
- hn = b;
+ if (!hn) {
+ r = read_etc_hostname(NULL, &b);
+ if (r < 0) {
+ if (r == -ENOENT)
+ enoent = true;
+ else
+ log_warning_errno(r, "Failed to read configured hostname: %m");
+ } else
+ hn = b;
+ }
if (isempty(hn)) {
- /* Don't override the hostname if it is already set
- * and not explicitly configured */
+ /* Don't override the hostname if it is already set and not explicitly configured */
if (hostname_is_set())
return 0;
Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options)
Mount.LazyUnmount, config_parse_bool, 0, offsetof(Mount, lazy_unmount)
Mount.ForceUnmount, config_parse_bool, 0, offsetof(Mount, force_unmount)
+Mount.ReadWriteOnly, config_parse_bool, 0, offsetof(Mount, read_write_only)
EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
const char *n;
ExecContext *c = data;
const Unit *u = userdata;
+ bool obsolete = false;
ExecOutput eo;
int r;
eo = EXEC_OUTPUT_NAMED_FD;
+ } else if (streq(rvalue, "syslog")) {
+ eo = EXEC_OUTPUT_JOURNAL;
+ obsolete = true;
+
+ } else if (streq(rvalue, "syslog+console")) {
+ eo = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+ obsolete = true;
+
} else if ((n = startswith(rvalue, "file:"))) {
r = unit_full_printf(u, n, &resolved);
}
}
+ if (obsolete)
+ log_syntax(unit, LOG_NOTICE, filename, line, 0,
+ "Standard output type %s is obsolete, automatically updating to %s. Please update your unit file, and consider removing the setting altogether.",
+ rvalue, exec_output_to_string(eo));
+
if (streq(lvalue, "StandardOutput")) {
if (eo == EXEC_OUTPUT_NAMED_FD)
free_and_replace(c->stdio_fdname[STDOUT_FILENO], resolved);
void *userdata) {
ExecContext *c = data;
- const Unit *u = userdata;
+ _unused_ const Unit *u = userdata;
bool invert = false;
const char *p;
int r;
void *userdata) {
ExecOutput t, *eo = data;
+ bool obsolete = false;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- t = exec_output_from_string(rvalue);
- if (t < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue);
- return 0;
- }
+ if (streq(rvalue, "syslog")) {
+ t = EXEC_OUTPUT_JOURNAL;
+ obsolete = true;
+ } else if (streq(rvalue, "syslog+console")) {
+ t = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
+ obsolete = true;
+ } else {
+ t = exec_output_from_string(rvalue);
+ if (t < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue);
+ return 0;
+ }
- if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
- return 0;
+ if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue);
+ return 0;
+ }
}
+ if (obsolete)
+ log_syntax(unit, LOG_NOTICE, filename, line, 0,
+ "Standard output type %s is obsolete, automatically updating to %s. Please update your configuration.",
+ rvalue, exec_output_to_string(t));
+
*eo = t;
return 0;
}
r = safe_atoi(rvalue, &priority);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid swap pririty '%s', ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid swap priority '%s', ignoring.", rvalue);
return 0;
}
ACTION_TEST,
ACTION_DUMP_CONFIGURATION_ITEMS,
ACTION_DUMP_BUS_PROPERTIES,
+ ACTION_BUS_INTROSPECT,
} arg_action = ACTION_RUN;
+static const char *arg_bus_introspect = NULL;
+
/* Those variables are initialized to 0 automatically, so we avoid uninitialized memory access.
* Real defaults are assigned in reset_arguments() below. */
static char *arg_default_unit;
static OOMPolicy arg_default_oom_policy;
static CPUSet arg_cpu_affinity;
static NUMAPolicy arg_numa_policy;
+static usec_t arg_clock_usec;
/* A copy of the original environment block */
static char **saved_env = NULL;
(void) parse_path_argument_and_warn(value, false, &arg_watchdog_device);
+ } else if (proc_cmdline_key_streq(key, "systemd.clock_usec")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = safe_atou64(value, &arg_clock_usec);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse systemd.clock_usec= argument, ignoring: %s", value);
+
} else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_INVALID)
assert(m);
- /* Propagates the various manager settings into the manager object, i.e. properties that effect the manager
- * itself (as opposed to just being inherited into newly allocated units, see set_manager_defaults() above). */
+ /* Propagates the various manager settings into the manager object, i.e. properties that
+ * effect the manager itself (as opposed to just being inherited into newly allocated
+ * units, see set_manager_defaults() above). */
m->confirm_spawn = arg_confirm_spawn;
m->service_watchdogs = arg_service_watchdogs;
- m->runtime_watchdog = arg_runtime_watchdog;
- m->reboot_watchdog = arg_reboot_watchdog;
- m->kexec_watchdog = arg_kexec_watchdog;
m->cad_burst_action = arg_cad_burst_action;
+ manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
+ manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
+ manager_set_watchdog(m, WATCHDOG_KEXEC, arg_kexec_watchdog);
+
manager_set_show_status(m, arg_show_status, "commandline");
m->status_unit_format = arg_status_unit_format;
}
ARG_VERSION,
ARG_DUMP_CONFIGURATION_ITEMS,
ARG_DUMP_BUS_PROPERTIES,
+ ARG_BUS_INTROSPECT,
ARG_DUMP_CORE,
ARG_CRASH_CHVT,
ARG_CRASH_SHELL,
{ "version", no_argument, NULL, ARG_VERSION },
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
{ "dump-bus-properties", no_argument, NULL, ARG_DUMP_BUS_PROPERTIES },
+ { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
{ "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT },
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
arg_action = ACTION_DUMP_BUS_PROPERTIES;
break;
+ case ARG_BUS_INTROSPECT:
+ arg_bus_introspect = optarg;
+ arg_action = ACTION_BUS_INTROSPECT;
+ break;
+
case ARG_DUMP_CORE:
if (!optarg)
arg_dump_core = true;
return log_oom();
printf("%s [OPTIONS...]\n\n"
- "Starts up and maintains the system or user services.\n\n"
+ "%sStarts and monitors system and user services.%s\n\n"
+ "This program takes no positional arguments.\n\n"
+ "%sOptions%s:\n"
" -h --help Show this help\n"
" --version Show version\n"
" --test Determine initial transaction, dump it and exit\n"
" --no-pager Do not pipe output into a pager\n"
" --dump-configuration-items Dump understood unit configuration items\n"
" --dump-bus-properties Dump exposed bus properties\n"
+ " --bus-introspect=PATH Write XML introspection data\n"
" --unit=UNIT Set default unit\n"
" --dump-core[=BOOL] Dump core on crash\n"
" --crash-vt=NR Change to specified VT on crash\n"
" --default-standard-error= Set default standard error output for services\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
+ , ansi_highlight(), ansi_normal()
+ , ansi_underline(), ansi_normal()
, link
);
static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
struct rlimit new_rlimit;
+ uint64_t mm;
int r;
/* BPF_MAP_TYPE_LPM_TRIE bpf maps are charged against RLIMIT_MEMLOCK, even if we have CAP_IPC_LOCK which should
* must be unsigned, hence this is a given, but let's make this clear here. */
assert_cc(RLIM_INFINITY > 0);
+ mm = physical_memory() / 8; /* Let's scale how much we allow to be locked by the amount of physical
+ * RAM. We allow an eighth to be locked by us, just to pick a value. */
+
new_rlimit = (struct rlimit) {
- .rlim_cur = MAX(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur),
- .rlim_max = MAX(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_max),
+ .rlim_cur = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur, mm),
+ .rlim_max = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_max, mm),
};
if (saved_rlimit->rlim_max >= new_rlimit.rlim_cur &&
static void initialize_clock(void) {
int r;
+ /* This is called very early on, before we parse the kernel command line or otherwise figure out why
+ * we are running, but only once. */
+
if (clock_is_localtime(NULL) > 0) {
int min;
log_info("System time before build time, advancing clock.");
}
+static void apply_clock_update(void) {
+ struct timespec ts;
+
+ /* This is called later than initialize_clock(), i.e. after we parsed configuration files/kernel
+ * command line and such. */
+
+ if (arg_clock_usec == 0)
+ return;
+
+ if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, arg_clock_usec)) < 0)
+ log_error_errno(errno, "Failed to set system clock to time specified on kernel command line: %m");
+ else {
+ char buf[FORMAT_TIMESTAMP_MAX];
+
+ log_info("Set system clock to %s, as specified on the kernel command line.",
+ format_timestamp(buf, sizeof(buf), arg_clock_usec));
+ }
+}
+
static void initialize_coredump(bool skip_setup) {
#if ENABLE_COREDUMP
if (getpid_cached() != 1)
(void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
set_manager_defaults(m);
+ set_manager_settings(m);
update_cpu_affinity(false);
update_numa_policy(false);
if (r < 0)
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device);
}
-
- if (timestamp_is_set(arg_runtime_watchdog))
- watchdog_set_timeout(&arg_runtime_watchdog);
}
if (arg_timer_slack_nsec != NSEC_INFINITY)
/* Note that this also parses bits from the kernel command line, including "debug". */
log_parse_environment();
- return 0;
-}
-
-static int load_configuration(
- int argc,
- char **argv,
- const struct rlimit *saved_rlimit_nofile,
- const struct rlimit *saved_rlimit_memlock,
- const char **ret_error_message) {
- int r;
-
- assert(saved_rlimit_nofile);
- assert(saved_rlimit_memlock);
- assert(ret_error_message);
-
- (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
-
- r = parse_argv(argc, argv);
- if (r < 0) {
- *ret_error_message = "Failed to parse commandline arguments";
- return r;
- }
-
/* Initialize the show status setting if it hasn't been set explicitly yet */
if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_YES;
(void) reset_all_signal_handlers();
(void) ignore_signals(SIGNALS_IGNORE, -1);
- r = load_configuration(argc, argv, &saved_rlimit_nofile, &saved_rlimit_memlock, &error_message);
- if (r < 0)
+ (void) parse_configuration(&saved_rlimit_nofile, &saved_rlimit_memlock);
+
+ r = parse_argv(argc, argv);
+ if (r < 0) {
+ error_message = "Failed to parse commandline arguments";
goto finish;
+ }
r = safety_checks();
if (r < 0)
goto finish;
- if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES))
+ if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP, ACTION_DUMP_CONFIGURATION_ITEMS, ACTION_DUMP_BUS_PROPERTIES, ACTION_BUS_INTROSPECT))
(void) pager_open(arg_pager_flags);
if (arg_action != ACTION_RUN)
dump_bus_properties(stdout);
retval = EXIT_SUCCESS;
goto finish;
+ } else if (arg_action == ACTION_BUS_INTROSPECT) {
+ r = bus_manager_introspect_implementations(stdout, arg_bus_introspect);
+ retval = r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ goto finish;
}
assert_se(IN_SET(arg_action, ACTION_RUN, ACTION_TEST));
assert_se(chdir("/") == 0);
if (arg_action == ACTION_RUN) {
+ /* Apply the systemd.clock_usec= kernel command line switch */
+ apply_clock_update();
/* A core pattern might have been specified via the cmdline. */
initialize_core_pattern(skip_setup);
pager_close();
if (m) {
- arg_reboot_watchdog = m->reboot_watchdog;
- arg_kexec_watchdog = m->kexec_watchdog;
+ arg_reboot_watchdog = manager_get_watchdog(m, WATCHDOG_REBOOT);
+ arg_kexec_watchdog = manager_get_watchdog(m, WATCHDOG_KEXEC);
m = manager_free(m);
}
static int manager_dispatch_timezone_change(sd_event_source *source, const struct inotify_event *event, void *userdata);
static int manager_run_environment_generators(Manager *m);
static int manager_run_generators(Manager *m);
+static void manager_vacuum(Manager *m);
static usec_t manager_watch_jobs_next_time(Manager *m) {
return usec_add(now(CLOCK_MONOTONIC),
}
}
-void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
+static void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
assert(m);
if (enable) {
.original_log_level = -1,
.original_log_target = _LOG_TARGET_INVALID,
+ .watchdog_overridden[WATCHDOG_RUNTIME] = USEC_INFINITY,
+ .watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
+ .watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
+
.notify_fd = -1,
.cgroups_agent_fd = -1,
.signal_fd = -1,
log_info("Populated /etc with preset unit settings.");
}
-static void manager_vacuum(Manager *m) {
- assert(m);
-
- /* Release any dynamic users no longer referenced */
- dynamic_user_vacuum(m, true);
-
- /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
- manager_vacuum_uid_refs(m);
- manager_vacuum_gid_refs(m);
-
- /* Release any runtimes no longer referenced */
- exec_runtime_vacuum(m);
-}
-
static void manager_ready(Manager *m) {
assert(m);
int r;
assert(m);
- assert(name || path);
assert(_ret);
/* This will prepare the unit for loading, but not actually
if (path && !is_path(path))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
- if (!name)
+ if (!name) {
+ /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
+ * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
+ * but this cannot be possible in any code path (See #6119). */
+ assert_se(path);
name = basename(path);
+ }
t = unit_name_to_type(name);
return 0;
}
+static bool manager_process_barrier_fd(char * const *tags, FDSet *fds) {
+
+ /* nothing else must be sent when using BARRIER=1 */
+ if (strv_contains(tags, "BARRIER=1")) {
+ if (strv_length(tags) == 1) {
+ if (fdset_size(fds) != 1)
+ log_warning("Got incorrect number of fds with BARRIER=1, closing them.");
+ } else
+ log_warning("Extra notification messages sent with BARRIER=1, ignoring everything.");
+
+ /* Drop the message if BARRIER=1 was found */
+ return true;
+ }
+
+ return false;
+}
+
static void manager_invoke_notify_message(
Manager *m,
Unit *u,
const struct ucred *ucred,
- const char *buf,
+ char * const *tags,
FDSet *fds) {
assert(m);
assert(u);
assert(ucred);
- assert(buf);
+ assert(tags);
if (u->notifygen == m->notifygen) /* Already invoked on this same unit in this same iteration? */
return;
u->notifygen = m->notifygen;
- if (UNIT_VTABLE(u)->notify_message) {
- _cleanup_strv_free_ char **tags = NULL;
-
- tags = strv_split(buf, NEWLINE);
- if (!tags) {
- log_oom();
- return;
- }
-
+ if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, ucred, tags, fds);
- } else if (DEBUG_LOGGING) {
- _cleanup_free_ char *x = NULL, *y = NULL;
+ else if (DEBUG_LOGGING) {
+ _cleanup_free_ char *buf = NULL, *x = NULL, *y = NULL;
- x = ellipsize(buf, 20, 90);
+ buf = strv_join(tags, ", ");
+ if (buf)
+ x = ellipsize(buf, 20, 90);
if (x)
y = cescape(x);
.iov_base = buf,
.iov_len = sizeof(buf)-1,
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
struct cmsghdr *cmsg;
struct ucred *ucred = NULL;
_cleanup_free_ Unit **array_copy = NULL;
+ _cleanup_strv_free_ char **tags = NULL;
Unit *u1, *u2, **array;
int r, *fd_array = NULL;
size_t n_fds = 0;
return 0;
}
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
- if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0; /* Spurious wakeup, try again */
-
- /* If this is any other, real error, then let's stop processing this socket. This of course means we
- * won't take notification messages anymore, but that's still better than busy looping around this:
- * being woken up over and over again but being unable to actually read the message off the socket. */
- return log_error_errno(errno, "Failed to receive notification message: %m");
- }
+ n = recvmsg_safe(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC|MSG_TRUNC);
+ if (IN_SET(n, -EAGAIN, -EINTR))
+ return 0; /* Spurious wakeup, try again */
+ if (n < 0)
+ /* If this is any other, real error, then let's stop processing this socket. This of course
+ * means we won't take notification messages anymore, but that's still better than busy
+ * looping around this: being woken up over and over again but being unable to actually read
+ * the message off the socket. */
+ return log_error_errno(n, "Failed to receive notification message: %m");
CMSG_FOREACH(cmsg, &msghdr) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ assert(!fd_array);
fd_array = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+ assert(!ucred);
ucred = (struct ucred*) CMSG_DATA(cmsg);
}
}
return 0;
}
- /* Make sure it's NUL-terminated. */
+ /* Make sure it's NUL-terminated, then parse it to obtain the tags list */
buf[n] = 0;
+ tags = strv_split_newlines(buf);
+ if (!tags) {
+ log_oom();
+ return 0;
+ }
+
+ /* possibly a barrier fd, let's see */
+ if (manager_process_barrier_fd(tags, fds))
+ return 0;
/* Increase the generation counter used for filtering out duplicate unit invocations. */
m->notifygen++;
/* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle duplicate units
* make sure we only invoke each unit's handler once. */
if (u1) {
- manager_invoke_notify_message(m, u1, ucred, buf, fds);
+ manager_invoke_notify_message(m, u1, ucred, tags, fds);
found = true;
}
if (u2) {
- manager_invoke_notify_message(m, u2, ucred, buf, fds);
+ manager_invoke_notify_message(m, u2, ucred, tags, fds);
found = true;
}
if (array_copy)
for (size_t i = 0; array_copy[i]; i++) {
- manager_invoke_notify_message(m, array_copy[i], ucred, buf, fds);
+ manager_invoke_notify_message(m, array_copy[i], ucred, tags, fds);
found = true;
}
return log_error_errno(r, "Failed to enable SIGCHLD event source: %m");
while (m->objective == MANAGER_OK) {
- usec_t wait_usec;
+ usec_t wait_usec, watchdog_usec;
- if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m))
+ watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
+ if (timestamp_is_set(watchdog_usec))
watchdog_ping();
if (!ratelimit_below(&rl)) {
continue;
/* Sleep for watchdog runtime wait time */
- if (MANAGER_IS_SYSTEM(m))
+ if (timestamp_is_set(watchdog_usec))
wait_usec = watchdog_runtime_wait();
else
wait_usec = USEC_INFINITY;
MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
}
+#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
+
+static void manager_serialize_uid_refs_internal(
+ Manager *m,
+ FILE *f,
+ Hashmap **uid_refs,
+ const char *field_name) {
+
+ Iterator i;
+ void *p, *k;
+
+ assert(m);
+ assert(f);
+ assert(uid_refs);
+ assert(field_name);
+
+ /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
+ * the actual counter of it is better rebuild after a reload/reexec. */
+
+ HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
+ uint32_t c;
+ uid_t uid;
+
+ uid = PTR_TO_UID(k);
+ c = PTR_TO_UINT32(p);
+
+ if (!(c & DESTROY_IPC_FLAG))
+ continue;
+
+ (void) serialize_item_format(f, field_name, UID_FMT, uid);
+ }
+}
+
+static void manager_serialize_uid_refs(Manager *m, FILE *f) {
+ manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
+}
+
+static void manager_serialize_gid_refs(Manager *m, FILE *f) {
+ manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
+}
+
int manager_serialize(
Manager *m,
FILE *f,
if (m->log_target_overridden)
(void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
+ (void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
+ (void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
+ (void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
+
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
_cleanup_free_ char *joined = NULL;
return 0;
}
+usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return USEC_INFINITY;
+
+ if (timestamp_is_set(m->watchdog_overridden[t]))
+ return m->watchdog_overridden[t];
+
+ return m->watchdog[t];
+}
+
+void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
+ int r = 0;
+
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return;
+
+ if (m->watchdog[t] == timeout)
+ return;
+
+ if (t == WATCHDOG_RUNTIME)
+ if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
+ if (timestamp_is_set(timeout))
+ r = watchdog_set_timeout(&timeout);
+ else
+ watchdog_close(true);
+ }
+
+ if (r >= 0)
+ m->watchdog[t] = timeout;
+}
+
+int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) {
+ int r = 0;
+
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return 0;
+
+ if (m->watchdog_overridden[t] == timeout)
+ return 0;
+
+ if (t == WATCHDOG_RUNTIME) {
+ usec_t *p;
+
+ p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
+ if (timestamp_is_set(*p))
+ r = watchdog_set_timeout(p);
+ else
+ watchdog_close(true);
+ }
+
+ if (r >= 0)
+ m->watchdog_overridden[t] = timeout;
+
+ return 0;
+}
+
+static void manager_deserialize_uid_refs_one_internal(
+ Manager *m,
+ Hashmap** uid_refs,
+ const char *value) {
+
+ uid_t uid;
+ uint32_t c;
+ int r;
+
+ assert(m);
+ assert(uid_refs);
+ assert(value);
+
+ r = parse_uid(value, &uid);
+ if (r < 0 || uid == 0) {
+ log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
+ return;
+ }
+
+ r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
+ if (r < 0) {
+ log_oom();
+ return;
+ }
+
+ c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
+ if (c & DESTROY_IPC_FLAG)
+ return;
+
+ c |= DESTROY_IPC_FLAG;
+
+ r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add UID reference entry: %m");
+ return;
+ }
+}
+
+static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
+ manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
+}
+
+static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
+ manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
+}
+
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
int r = 0;
else
manager_override_log_target(m, target);
+ } else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_set_watchdog_overridden(m, WATCHDOG_RUNTIME, t);
+
+ } else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_set_watchdog_overridden(m, WATCHDOG_REBOOT, t);
+
+ } else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
+ usec_t t;
+
+ if (deserialize_usec(val, &t) < 0)
+ log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
+ else
+ manager_set_watchdog_overridden(m, WATCHDOG_KEXEC, t);
+
} else if (startswith(l, "env=")) {
r = deserialize_environment(l + 4, &m->client_environment);
if (r < 0)
return MANAGER_RUNNING;
}
-#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
-
static void manager_unref_uid_internal(
Manager *m,
Hashmap **uid_refs,
}
}
-void manager_vacuum_uid_refs(Manager *m) {
+static void manager_vacuum_uid_refs(Manager *m) {
manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid);
}
-void manager_vacuum_gid_refs(Manager *m) {
+static void manager_vacuum_gid_refs(Manager *m) {
manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid);
}
-static void manager_serialize_uid_refs_internal(
- Manager *m,
- FILE *f,
- Hashmap **uid_refs,
- const char *field_name) {
-
- Iterator i;
- void *p, *k;
-
- assert(m);
- assert(f);
- assert(uid_refs);
- assert(field_name);
-
- /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as the actual counter
- * of it is better rebuild after a reload/reexec. */
-
- HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
- uint32_t c;
- uid_t uid;
-
- uid = PTR_TO_UID(k);
- c = PTR_TO_UINT32(p);
-
- if (!(c & DESTROY_IPC_FLAG))
- continue;
-
- (void) serialize_item_format(f, field_name, UID_FMT, uid);
- }
-}
-
-void manager_serialize_uid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
-}
-
-void manager_serialize_gid_refs(Manager *m, FILE *f) {
- manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
-}
-
-static void manager_deserialize_uid_refs_one_internal(
- Manager *m,
- Hashmap** uid_refs,
- const char *value) {
-
- uid_t uid;
- uint32_t c;
- int r;
-
+static void manager_vacuum(Manager *m) {
assert(m);
- assert(uid_refs);
- assert(value);
-
- r = parse_uid(value, &uid);
- if (r < 0 || uid == 0) {
- log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
- return;
- }
-
- r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
- if (r < 0) {
- log_oom();
- return;
- }
-
- c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
- if (c & DESTROY_IPC_FLAG)
- return;
-
- c |= DESTROY_IPC_FLAG;
- r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
- if (r < 0) {
- log_debug_errno(r, "Failed to add UID reference entry: %m");
- return;
- }
-}
+ /* Release any dynamic users no longer referenced */
+ dynamic_user_vacuum(m, true);
-void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
- manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
-}
+ /* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
+ manager_vacuum_uid_refs(m);
+ manager_vacuum_gid_refs(m);
-void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
- manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
+ /* Release any runtimes no longer referenced */
+ exec_runtime_vacuum(m);
}
int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
_MANAGER_TIMESTAMP_INVALID = -1,
} ManagerTimestamp;
+typedef enum WatchdogType {
+ WATCHDOG_RUNTIME,
+ WATCHDOG_REBOOT,
+ WATCHDOG_KEXEC,
+ _WATCHDOG_TYPE_MAX,
+} WatchdogType;
+
#include "execute.h"
#include "job.h"
#include "path-lookup.h"
char **transient_environment; /* The environment, as determined from config files, kernel cmdline and environment generators */
char **client_environment; /* Environment variables created by clients through the bus API */
- usec_t runtime_watchdog;
- usec_t reboot_watchdog;
- usec_t kexec_watchdog;
+ usec_t watchdog[_WATCHDOG_TYPE_MAX];
+ usec_t watchdog_overridden[_WATCHDOG_TYPE_MAX];
dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX];
void manager_set_first_boot(Manager *m, bool b);
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
-void manager_flip_auto_status(Manager *m, bool enable, const char *reason);
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now);
int manager_ref_gid(Manager *m, gid_t gid, bool destroy_now);
-void manager_vacuum_uid_refs(Manager *m);
-void manager_vacuum_gid_refs(Manager *m);
-
-void manager_serialize_uid_refs(Manager *m, FILE *f);
-void manager_deserialize_uid_refs_one(Manager *m, const char *value);
-
-void manager_serialize_gid_refs(Manager *m, FILE *f);
-void manager_deserialize_gid_refs_one(Manager *m, const char *value);
-
char *manager_taint_string(Manager *m);
void manager_ref_console(Manager *m);
ManagerTimestamp manager_timestamp_from_string(const char *s) _pure_;
ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);
+usec_t manager_get_watchdog(Manager *m, WatchdogType t);
+void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
+int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout);
+
const char* oom_policy_to_string(OOMPolicy i) _const_;
OOMPolicy oom_policy_from_string(const char *s) _pure_;
#include "macro.h"
#include "mkdir.h"
#include "mount-setup.h"
+#include "mount-util.h"
#include "mountpoint-util.h"
#include "nulstr-util.h"
#include "path-util.h"
#endif
static const MountPoint mount_table[] = {
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_STRICTATIME,
+ { "devtmpfs", "/dev", "devtmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_NOEXEC|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
#if ENABLE_SMACK
- { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
mac_smack_use, MNT_FATAL },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
mac_smack_use, MNT_FATAL },
#endif
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
+ { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
NULL, MNT_IN_CONTAINER },
#if ENABLE_SMACK
- { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
mac_smack_use, MNT_FATAL },
#endif
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
- { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
#if ENABLE_EFI
- { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
is_efi_boot, MNT_NONE },
#endif
- { "bpf", "/sys/fs/bpf", "bpf", "mode=700", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "bpf", "/sys/fs/bpf", "bpf", "mode=700", MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE, },
};
}
/* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
- (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
+ (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755" TMPFS_LIMITS_SYS_FS_CGROUP);
return 0;
}
MOUNT_CLEANING);
}
+static bool mount_is_automount(const MountParameters *p) {
+ assert(p);
+
+ return fstab_test_option(p->options,
+ "comment=systemd.automount\0"
+ "x-systemd.automount\0");
+}
+
static bool mount_is_network(const MountParameters *p) {
assert(p);
return false;
}
+static bool mount_is_nofail(const Mount *m) {
+ assert(m);
+
+ if (!m->from_fragment)
+ return false;
+
+ return fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0");
+}
+
static bool mount_is_loop(const MountParameters *p) {
assert(p);
MountParameters *p;
assert(m);
- /* Returns true for all units that are "magic" and should be excluded from the usual start-up and shutdown
- * dependencies. We call them "extrinsic" here, as they are generally mounted outside of the systemd dependency
- * logic. We shouldn't attempt to manage them ourselves but it's fine if the user operates on them with us. */
+ /* Returns true for all units that are "magic" and should be excluded from the usual
+ * start-up and shutdown dependencies. We call them "extrinsic" here, as they are generally
+ * mounted outside of the systemd dependency logic. We shouldn't attempt to manage them
+ * ourselves but it's fine if the user operates on them with us. */
- if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) /* We only automatically manage mounts if we are in system mode */
+ /* We only automatically manage mounts if we are in system mode */
+ if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return true;
if (UNIT(m)->perpetual) /* All perpetual units never change state */
return true;
- if (PATH_IN_SET(m->where, /* Don't bother with the OS data itself */
- "/", /* (strictly speaking redundant: should already be covered by the perpetual flag check above) */
- "/usr",
- "/etc"))
- return true;
-
- if (PATH_STARTSWITH_SET(m->where,
- "/run/initramfs", /* This should stay around from before we boot until after we shutdown */
- "/proc", /* All of this is API VFS */
- "/sys", /* … dito … */
- "/dev")) /* … dito … */
- return true;
-
- /* If this is an initrd mount, and we are not in the initrd, then leave this around forever, too. */
p = get_mount_parameters(m);
- if (p && fstab_test_option(p->options, "x-initrd.mount\0") && !in_initrd())
+ if (p && fstab_is_extrinsic(m->where, p->options))
return true;
return false;
}
+static int mount_add_default_ordering_dependencies(
+ Mount *m,
+ MountParameters *p,
+ UnitDependencyMask mask) {
+
+ const char *after, *before, *e;
+ int r;
+
+ assert(m);
+
+ e = path_startswith(m->where, "/sysroot");
+ if (e && in_initrd()) {
+ /* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW,
+ * it's not technically part of the basic initrd filesystem itself, and so
+ * shouldn't inherit the default Before=local-fs.target dependency. */
+
+ after = NULL;
+ before = isempty(e) ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_INITRD_FS_TARGET;
+
+ } else if (mount_is_network(p)) {
+ after = SPECIAL_REMOTE_FS_PRE_TARGET;
+ before = SPECIAL_REMOTE_FS_TARGET;
+
+ } else {
+ after = SPECIAL_LOCAL_FS_PRE_TARGET;
+ before = SPECIAL_LOCAL_FS_TARGET;
+ }
+
+ if (!mount_is_nofail(m) && !mount_is_automount(p)) {
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
+ if (r < 0)
+ return r;
+ }
+
+ if (after) {
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
+ if (r < 0)
+ return r;
+ }
+
+ return unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS,
+ SPECIAL_UMOUNT_TARGET, true, mask);
+}
+
static int mount_add_default_dependencies(Mount *m) {
- const char *after, *before;
UnitDependencyMask mask;
MountParameters *p;
- bool nofail;
int r;
assert(m);
if (!UNIT(m)->default_dependencies)
return 0;
- /* We do not add any default dependencies to /, /usr or /run/initramfs/, since they are guaranteed to stay
- * mounted the whole time, since our system is on it. Also, don't bother with anything mounted below virtual
- * file systems, it's also going to be virtual, and hence not worth the effort. */
+ /* We do not add any default dependencies to /, /usr or /run/initramfs/, since they are
+ * guaranteed to stay mounted the whole time, since our system is on it. Also, don't
+ * bother with anything mounted below virtual file systems, it's also going to be virtual,
+ * and hence not worth the effort. */
if (mount_is_extrinsic(m))
return 0;
return 0;
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
- nofail = m->from_fragment ? fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0") : false;
+
+ r = mount_add_default_ordering_dependencies(m, p, mask);
+ if (r < 0)
+ return r;
if (mount_is_network(p)) {
- /* We order ourselves after network.target. This is
- * primarily useful at shutdown: services that take
- * down the network should order themselves before
- * network.target, so that they are shut down only
- * after this mount unit is stopped. */
+ /* We order ourselves after network.target. This is primarily useful at shutdown:
+ * services that take down the network should order themselves before
+ * network.target, so that they are shut down only after this mount unit is
+ * stopped. */
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, true, mask);
if (r < 0)
return r;
- /* We pull in network-online.target, and order
- * ourselves after it. This is useful at start-up to
- * actively pull in tools that want to be started
- * before we start mounting network file systems, and
- * whose purpose it is to delay this until the network
- * is "up". */
+ /* We pull in network-online.target, and order ourselves after it. This is useful
+ * at start-up to actively pull in tools that want to be started before we start
+ * mounting network file systems, and whose purpose it is to delay this until the
+ * network is "up". */
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, true, mask);
if (r < 0)
return r;
-
- after = SPECIAL_REMOTE_FS_PRE_TARGET;
- before = SPECIAL_REMOTE_FS_TARGET;
- } else {
- after = SPECIAL_LOCAL_FS_PRE_TARGET;
- before = SPECIAL_LOCAL_FS_TARGET;
}
- if (!nofail) {
- r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
- if (r < 0)
- return r;
- }
-
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, mask);
- if (r < 0)
- return r;
-
/* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
if (streq_ptr(p->fstype, "tmpfs")) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, true, mask);
"%sSloppyOptions: %s\n"
"%sLazyUnmount: %s\n"
"%sForceUnmount: %s\n"
+ "%sReadWriteOnly: %s\n"
"%sTimeoutSec: %s\n",
prefix, mount_state_to_string(m->state),
prefix, mount_result_to_string(m->result),
prefix, yes_no(m->sloppy_options),
prefix, yes_no(m->lazy_unmount),
prefix, yes_no(m->force_unmount),
+ prefix, yes_no(m->read_write_only),
prefix, format_timespan(buf, sizeof(buf), m->timeout_usec, USEC_PER_SEC));
if (m->control_pid > 0)
r = exec_command_set(m->control_command, MOUNT_PATH, p->what, m->where, NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
+ if (r >= 0 && m->read_write_only)
+ r = exec_command_append(m->control_command, "-w", NULL);
if (r >= 0 && p->fstype)
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
if (r >= 0 && !isempty(opts))
"-o", o, NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
+ if (r >= 0 && m->read_write_only)
+ r = exec_command_append(m->control_command, "-w", NULL);
if (r >= 0 && p->fstype)
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
} else
/* Remember that this device might just have disappeared */
if (set_ensure_allocated(&gone, &path_hash_ops) < 0 ||
- set_put_strdup(gone, mount->parameters_proc_self_mountinfo.what) < 0)
+ set_put_strdup(&gone, mount->parameters_proc_self_mountinfo.what) < 0)
log_oom(); /* we don't care too much about OOM here... */
}
/* Track devices currently used */
if (set_ensure_allocated(&around, &path_hash_ops) < 0 ||
- set_put_strdup(around, mount->parameters_proc_self_mountinfo.what) < 0)
+ set_put_strdup(&around, mount->parameters_proc_self_mountinfo.what) < 0)
log_oom();
}
.control_pid = mount_control_pid,
- .bus_vtable = bus_mount_vtable,
.bus_set_property = bus_mount_set_property,
.bus_commit_properties = bus_mount_commit_properties,
bool lazy_unmount;
bool force_unmount;
+ bool read_write_only;
+
MountResult result;
MountResult reload_result;
MountResult clean_result;
/* ProtectHome=tmpfs table */
static const MountEntry protect_home_tmpfs_table[] = {
- { "/home", TMPFS, true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
- { "/run/user", TMPFS, true, .read_only = true, .options_const = "mode=0755", .flags = MS_NODEV|MS_STRICTATIME },
- { "/root", TMPFS, true, .read_only = true, .options_const = "mode=0700", .flags = MS_NODEV|MS_STRICTATIME },
+ { "/home", TMPFS, true, .read_only = true, .options_const = "mode=0755" TMPFS_LIMITS_EMPTY_OR_ALMOST, .flags = MS_NODEV|MS_STRICTATIME },
+ { "/run/user", TMPFS, true, .read_only = true, .options_const = "mode=0755" TMPFS_LIMITS_EMPTY_OR_ALMOST, .flags = MS_NODEV|MS_STRICTATIME },
+ { "/root", TMPFS, true, .read_only = true, .options_const = "mode=0700" TMPFS_LIMITS_EMPTY_OR_ALMOST, .flags = MS_NODEV|MS_STRICTATIME },
};
/* ProtectHome=yes table */
.mode = EMPTY_DIR,
.ignore = false,
.read_only = true,
- .options_const = "mode=755",
+ .options_const = "mode=755" TMPFS_LIMITS_EMPTY_OR_ALMOST,
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
};
}
"Path is not absolute: %s",
t->path);
- str = strjoin("mode=0755,", t->options);
+ str = strjoin("mode=0755" TMPFS_LIMITS_TEMPORARY_FS ",", t->options);
if (!str)
return -ENOMEM;
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
- if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
+ if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755" TMPFS_LIMITS_DEV) < 0) {
r = log_debug_errno(errno, "Failed to mount tmpfs on '%s': %m", dev);
goto fail;
}
r = 0;
finish:
- for (m = mounts; m < mounts + n_mounts; m++)
- mount_entry_done(m);
+ if (n_mounts > 0)
+ for (m = mounts; m < mounts + n_mounts; m++)
+ mount_entry_done(m);
free(mounts);
}
static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
- fprintf(f,
- "%s%s: %s\n",
- prefix,
- path_type_to_string(s->type),
- s->path);
+ const char *type;
+
+ assert_se(type = path_type_to_string(s->type));
+ fprintf(f, "%s%s: %s\n", prefix, type, s->path);
}
void path_spec_done(PathSpec *s) {
(void) serialize_item(f, "result", path_result_to_string(p->result));
LIST_FOREACH(spec, s, p->specs) {
+ const char *type;
_cleanup_free_ char *escaped = NULL;
escaped = cescape(s->path);
if (!escaped)
return log_oom();
+ assert_se(type = path_type_to_string(s->type));
(void) serialize_item_format(f, "path-spec", "%s %i %s",
- path_type_to_string(s->type),
+ type,
s->previous_exists,
s->path);
}
.reset_failed = path_reset_failed,
- .bus_vtable = bus_path_vtable,
.bus_set_property = bus_path_set_property,
};
.kill = scope_kill,
+ .freeze = unit_freeze_vtable_common,
+ .thaw = unit_thaw_vtable_common,
+
.get_timeout = scope_get_timeout,
.serialize = scope_serialize,
.notify_cgroup_empty = scope_notify_cgroup_empty_event,
- .bus_vtable = bus_scope_vtable,
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
if (getfilecon_raw(path, &fcon) < 0) {
r = -errno;
- log_warning_errno(r, "SELinux getfilecon_raw on '%s' failed%s (perm=%s): %m",
+ log_warning_errno(r, "SELinux getfilecon_raw() on '%s' failed%s (perm=%s): %m",
path,
enforce ? "" : ", ignoring",
permission);
if (getcon_raw(&fcon) < 0) {
r = -errno;
- log_warning_errno(r, "SELinux getcon_raw failed%s (perm=%s): %m",
+ log_warning_errno(r, "SELinux getcon_raw() failed%s (perm=%s): %m",
enforce ? "" : ", ignoring",
permission);
if (!enforce)
int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
-#if HAVE_SELINUX
-
#define mac_selinux_access_check(message, permission, error) \
mac_selinux_generic_access_check((message), NULL, (permission), (error))
#define mac_selinux_unit_access_check(unit, message, permission, error) \
mac_selinux_generic_access_check((message), unit_label_path(unit), (permission), (error))
-
-#else
-
-#define mac_selinux_access_check(message, permission, error) 0
-#define mac_selinux_unit_access_check(unit, message, permission, error) 0
-
-#endif
return 0;
}
-static int service_add_fd_store(Service *s, int fd, const char *name) {
+static int service_add_fd_store(Service *s, int fd, const char *name, bool do_poll) {
ServiceFDStore *fs;
int r;
fs->fd = fd;
fs->service = s;
+ fs->do_poll = do_poll;
fs->fdname = strdup(name ?: "stored");
if (!fs->fdname) {
free(fs);
return -ENOMEM;
}
- r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
- if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
- free(fs->fdname);
- free(fs);
- return r;
- } else if (r >= 0)
- (void) sd_event_source_set_description(fs->event_source, "service-fd-store");
+ if (do_poll) {
+ r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
+ if (r < 0 && r != -EPERM) { /* EPERM indicates fds that aren't pollable, which is OK */
+ free(fs->fdname);
+ free(fs);
+ return r;
+ } else if (r >= 0)
+ (void) sd_event_source_set_description(fs->event_source, "service-fd-store");
+ }
LIST_PREPEND(fd_store, s->fd_store, fs);
s->n_fd_store++;
return 1; /* fd newly stored */
}
-static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
+static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name, bool do_poll) {
int r;
assert(s);
if (fd < 0)
break;
- r = service_add_fd_store(s, fd, name);
+ r = service_add_fd_store(s, fd, name, do_poll);
if (r == -EXFULL)
return log_unit_warning_errno(UNIT(s), r,
"Cannot store more fds than FileDescriptorStoreMax=%u, closing remaining.",
if (!c)
return log_oom();
- (void) serialize_item_format(f, "fd-store-fd", "%i %s", copy, c);
+ (void) serialize_item_format(f, "fd-store-fd", "%i \"%s\" %i", copy, c, fs->do_poll);
}
if (s->main_exec_status.pid > 0) {
s->socket_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "fd-store-fd")) {
- const char *fdv;
- size_t pf;
+ _cleanup_free_ char *fdv = NULL, *fdn = NULL, *fdp = NULL;
int fd;
+ int do_poll;
- pf = strcspn(value, WHITESPACE);
- fdv = strndupa(value, pf);
-
- if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ r = extract_first_word(&value, &fdv, NULL, 0);
+ if (r <= 0 || safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) {
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
- else {
- _cleanup_free_ char *t = NULL;
- const char *fdn;
+ return 0;
+ }
- fdn = value + pf;
- fdn += strspn(fdn, WHITESPACE);
- (void) cunescape(fdn, 0, &t);
+ r = extract_first_word(&value, &fdn, NULL, EXTRACT_CUNESCAPE | EXTRACT_UNQUOTE);
+ if (r <= 0) {
+ log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
+ return 0;
+ }
- r = service_add_fd_store(s, fd, t);
- if (r < 0)
- log_unit_error_errno(u, r, "Failed to add fd to store: %m");
- else
- fdset_remove(fds, fd);
+ r = extract_first_word(&value, &fdp, NULL, 0);
+ if (r == 0) {
+ /* If the value is not present, we assume the default */
+ do_poll = 1;
+ } else if (r < 0 || safe_atoi(fdp, &do_poll) < 0) {
+ log_unit_debug_errno(u, r, "Failed to parse fd-store-fd value \"%s\": %m", value);
+ return 0;
}
+ r = service_add_fd_store(s, fd, fdn, do_poll);
+ if (r < 0)
+ log_unit_error_errno(u, r, "Failed to add fd to store: %m");
+ else
+ fdset_remove(fds, fd);
} else if (streq(key, "main-exec-status-pid")) {
pid_t pid;
return 0;
}
-static bool service_notify_message_authorized(Service *s, pid_t pid, char **tags, FDSet *fds) {
+static bool service_notify_message_authorized(Service *s, pid_t pid, FDSet *fds) {
assert(s);
if (s->notify_access == NOTIFY_NONE) {
static void service_notify_message(
Unit *u,
const struct ucred *ucred,
- char **tags,
+ char * const *tags,
FDSet *fds) {
Service *s = SERVICE(u);
bool notify_dbus = false;
const char *e;
- char **i;
+ char * const *i;
int r;
assert(u);
assert(ucred);
- if (!service_notify_message_authorized(SERVICE(u), ucred->pid, tags, fds))
+ if (!service_notify_message_authorized(SERVICE(u), ucred->pid, fds))
return;
if (DEBUG_LOGGING) {
name = NULL;
}
- (void) service_add_fd_store_set(s, fds, name);
+ (void) service_add_fd_store_set(s, fds, name, !strv_contains(tags, "FDPOLL=0"));
}
/* Notify clients about changed status or main pid */
.clean = service_clean,
.can_clean = service_can_clean,
+ .freeze = unit_freeze_vtable_common,
+ .thaw = unit_thaw_vtable_common,
+
.serialize = service_serialize,
.deserialize_item = service_deserialize_item,
.bus_name_owner_change = service_bus_name_owner_change,
- .bus_vtable = bus_service_vtable,
.bus_set_property = bus_service_set_property,
.bus_commit_properties = bus_service_commit_properties,
int fd;
char *fdname;
sd_event_source *event_source;
+ bool do_poll;
LIST_FIELDS(ServiceFDStore, fd_store);
};
#include "alloc-util.h"
#include "dbus-slice.h"
#include "dbus-unit.h"
+#include "fd-util.h"
#include "log.h"
#include "serialize.h"
#include "slice.h"
(void) slice_make_perpetual(m, SPECIAL_SYSTEM_SLICE, NULL);
}
+static bool slice_freezer_action_supported_by_children(Unit *s) {
+ Unit *member;
+ void *v;
+ Iterator i;
+
+ assert(s);
+
+ HASHMAP_FOREACH_KEY(v, member, s->dependencies[UNIT_BEFORE], i) {
+ int r;
+
+ if (UNIT_DEREF(member->slice) != s)
+ continue;
+
+ if (member->type == UNIT_SLICE) {
+ r = slice_freezer_action_supported_by_children(member);
+ if (!r)
+ return r;
+ }
+
+ if (!UNIT_VTABLE(member)->freeze)
+ return false;
+ }
+
+ return true;
+}
+
+static int slice_freezer_action(Unit *s, FreezerAction action) {
+ Unit *member;
+ void *v;
+ Iterator i;
+ int r;
+
+ assert(s);
+ assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+ if (!slice_freezer_action_supported_by_children(s))
+ return log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice");
+
+ HASHMAP_FOREACH_KEY(v, member, s->dependencies[UNIT_BEFORE], i) {
+ if (UNIT_DEREF(member->slice) != s)
+ continue;
+
+ if (action == FREEZER_FREEZE)
+ r = UNIT_VTABLE(member)->freeze(member);
+ else
+ r = UNIT_VTABLE(member)->thaw(member);
+
+ if (r < 0)
+ return r;
+ }
+
+ r = unit_cgroup_freezer_action(s, action);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int slice_freeze(Unit *s) {
+ assert(s);
+
+ return slice_freezer_action(s, FREEZER_FREEZE);
+}
+
+static int slice_thaw(Unit *s) {
+ assert(s);
+
+ return slice_freezer_action(s, FREEZER_THAW);
+}
+
+static bool slice_can_freeze(Unit *s) {
+ assert(s);
+
+ return slice_freezer_action_supported_by_children(s);
+}
+
const UnitVTable slice_vtable = {
.object_size = sizeof(Slice),
.cgroup_context_offset = offsetof(Slice, cgroup_context),
.kill = slice_kill,
+ .freeze = slice_freeze,
+ .thaw = slice_thaw,
+ .can_freeze = slice_can_freeze,
+
.serialize = slice_serialize,
.deserialize_item = slice_deserialize_item,
.active_state = slice_active_state,
.sub_state_to_string = slice_sub_state_to_string,
- .bus_vtable = bus_slice_vtable,
.bus_set_property = bus_slice_set_property,
.bus_commit_properties = bus_slice_commit_properties,
.control_pid = socket_control_pid,
- .bus_vtable = bus_socket_vtable,
.bus_set_property = bus_socket_set_property,
.bus_commit_properties = bus_socket_commit_properties,
.control_pid = swap_control_pid,
- .bus_vtable = bus_swap_vtable,
.bus_set_property = bus_swap_set_property,
.bus_commit_properties = bus_swap_commit_properties,
.active_state = target_active_state,
.sub_state_to_string = target_sub_state_to_string,
- .bus_vtable = bus_target_vtable,
-
.status_message_formats = {
.finished_start_job = {
[JOB_DONE] = "Reached target %s.",
.time_change = timer_time_change,
.timezone_change = timer_timezone_change,
- .bus_vtable = bus_timer_vtable,
.bus_set_property = bus_timer_set_property,
};
* %u: the username of the running user
*
* %m: the machine ID of the running system
- * %H: the host name of the running system
* %b: the boot ID of the running system
+ * %H: the hostname of the running system
+ * %v: the kernel version
+ * %a: the native userspace architecture
+ * %o: the OS ID according to /etc/os-release
+ * %w: the OS version ID, according to /etc/os-release
+ * %B: the OS build ID, according to /etc/os-release
+ * %W: the OS variant ID, according to /etc/os-release
*/
const Specifier table[] = {
{ 'u', specifier_user_name, NULL },
{ 'm', specifier_machine_id, NULL },
- { 'H', specifier_host_name, NULL },
{ 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
+ { 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
{}
};
{ 'm', specifier_machine_id, NULL },
{ 'H', specifier_host_name, NULL },
+ { 'l', specifier_short_host_name, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'v', specifier_kernel_release, NULL },
{}
sd_bus_slot_unref(u->match_bus_slot);
sd_bus_track_unref(u->bus_track);
u->deserialized_refs = strv_free(u->deserialized_refs);
+ u->pending_freezer_message = sd_bus_message_unref(u->pending_freezer_message);
unit_free_requires_mounts_for(u);
free(u);
}
+FreezerState unit_freezer_state(Unit *u) {
+ assert(u);
+
+ return u->freezer_state;
+}
+
+int unit_freezer_state_kernel(Unit *u, FreezerState *ret) {
+ char *values[1] = {};
+ int r;
+
+ assert(u);
+
+ r = cg_get_keyed_attribute(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events",
+ STRV_MAKE("frozen"), values);
+ if (r < 0)
+ return r;
+
+ r = _FREEZER_STATE_INVALID;
+
+ if (values[0]) {
+ if (streq(values[0], "0"))
+ r = FREEZER_RUNNING;
+ else if (streq(values[0], "1"))
+ r = FREEZER_FROZEN;
+ }
+
+ free(values[0]);
+ *ret = r;
+
+ return 0;
+}
+
UnitActiveState unit_active_state(Unit *u) {
assert(u);
if (!IN_SET(c->std_output,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
- EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+ EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE) &&
!IN_SET(c->std_error,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
- EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
+ EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE) &&
!c->log_namespace)
return 0;
}
static bool unit_test_condition(Unit *u) {
+ _cleanup_strv_free_ char **env = NULL;
+ int r;
+
assert(u);
dual_timestamp_get(&u->condition_timestamp);
- u->condition_result = condition_test_list(u->conditions, condition_type_to_string, log_unit_internal, u);
- unit_add_to_dbus_queue(u);
+ r = manager_get_effective_environment(u->manager, &env);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
+ u->condition_result = CONDITION_ERROR;
+ } else
+ u->condition_result = condition_test_list(
+ u->conditions,
+ env,
+ condition_type_to_string,
+ log_unit_internal,
+ u);
+ unit_add_to_dbus_queue(u);
return u->condition_result;
}
static bool unit_test_assert(Unit *u) {
+ _cleanup_strv_free_ char **env = NULL;
+ int r;
+
assert(u);
dual_timestamp_get(&u->assert_timestamp);
- u->assert_result = condition_test_list(u->asserts, assert_type_to_string, log_unit_internal, u);
- unit_add_to_dbus_queue(u);
+ r = manager_get_effective_environment(u->manager, &env);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Failed to determine effective environment: %m");
+ u->assert_result = CONDITION_ERROR;
+ } else
+ u->assert_result = condition_test_list(
+ u->asserts,
+ env,
+ assert_type_to_string,
+ log_unit_internal,
+ u);
+ unit_add_to_dbus_queue(u);
return u->assert_result;
}
* waits for a holdoff timer to elapse before it will start again. */
unit_add_to_dbus_queue(u);
+ unit_cgroup_freezer_action(u, FREEZER_THAW);
return UNIT_VTABLE(u)->start(u);
}
return -EBADR;
unit_add_to_dbus_queue(u);
+ unit_cgroup_freezer_action(u, FREEZER_THAW);
return UNIT_VTABLE(u)->stop(u);
}
return 0;
}
+ unit_cgroup_freezer_action(u, FREEZER_THAW);
+
return UNIT_VTABLE(u)->reload(u);
}
if (m == 0) {
/* The array is now empty, remove the entire entry */
- assert(hashmap_remove(u->manager->watch_pids, PID_TO_PTR(-pid)) == array);
+ assert_se(hashmap_remove(u->manager->watch_pids, PID_TO_PTR(-pid)) == array);
free(array);
}
}
return 0;
}
- if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) {
- log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type));
- return 0;
- }
-
- if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) {
- log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type));
+ /* Note that ordering a device unit after a unit is permitted since it
+ * allows to start its job running timeout at a specific time. */
+ if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) {
+ log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
return 0;
}
if (!sd_id128_is_null(u->invocation_id))
(void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id));
+ (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u)));
+
bus_track_serialize(u->bus_track, f, "ref");
for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m");
}
+ continue;
+ } else if (streq(l, "freezer-state")) {
+ FreezerState s;
+
+ s = freezer_state_from_string(v);
+ if (s < 0)
+ log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v);
+ else
+ u->freezer_state = s;
+
continue;
}
u->unit_file_preset = unit_file_query_preset(
u->manager->unit_file_scope,
NULL,
- basename(u->fragment_path));
+ basename(u->fragment_path),
+ NULL);
return u->unit_file_preset;
}
/* Make sure the drop-in dir is registered in our path cache. This way we don't need to stupidly
* recreate the cache after every drop-in we write. */
if (u->manager->unit_path_cache) {
- r = set_put_strdup(u->manager->unit_path_cache, p);
+ r = set_put_strdup(&u->manager->unit_path_cache, p);
if (r < 0)
return r;
}
return UNIT_VTABLE(u)->can_clean(u, ret);
}
+bool unit_can_freeze(Unit *u) {
+ assert(u);
+
+ if (UNIT_VTABLE(u)->can_freeze)
+ return UNIT_VTABLE(u)->can_freeze(u);
+
+ return UNIT_VTABLE(u)->freeze;
+}
+
+void unit_frozen(Unit *u) {
+ assert(u);
+
+ u->freezer_state = FREEZER_FROZEN;
+
+ bus_unit_send_pending_freezer_message(u);
+}
+
+void unit_thawed(Unit *u) {
+ assert(u);
+
+ u->freezer_state = FREEZER_RUNNING;
+
+ bus_unit_send_pending_freezer_message(u);
+}
+
+static int unit_freezer_action(Unit *u, FreezerAction action) {
+ UnitActiveState s;
+ int (*method)(Unit*);
+ int r;
+
+ assert(u);
+ assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
+
+ method = action == FREEZER_FREEZE ? UNIT_VTABLE(u)->freeze : UNIT_VTABLE(u)->thaw;
+ if (!method || !cg_freezer_supported())
+ return -EOPNOTSUPP;
+
+ if (u->job)
+ return -EBUSY;
+
+ if (u->load_state != UNIT_LOADED)
+ return -EHOSTDOWN;
+
+ s = unit_active_state(u);
+ if (s != UNIT_ACTIVE)
+ return -EHOSTDOWN;
+
+ if (IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING))
+ return -EALREADY;
+
+ r = method(u);
+ if (r <= 0)
+ return r;
+
+ return 1;
+}
+
+int unit_freeze(Unit *u) {
+ return unit_freezer_action(u, FREEZER_FREEZE);
+}
+
+int unit_thaw(Unit *u) {
+ return unit_freezer_action(u, FREEZER_THAW);
+}
+
+/* Wrappers around low-level cgroup freezer operations common for service and scope units */
+int unit_freeze_vtable_common(Unit *u) {
+ return unit_cgroup_freezer_action(u, FREEZER_FREEZE);
+}
+
+int unit_thaw_vtable_common(Unit *u) {
+ return unit_cgroup_freezer_action(u, FREEZER_THAW);
+}
+
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
UnitLoadState load_state;
Unit *merged_into;
+ FreezerState freezer_state;
+ sd_bus_message *pending_freezer_message;
+
char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
char *instance;
/* Clear out the various runtime/state/cache/logs/configuration data */
int (*clean)(Unit *u, ExecCleanMask m);
+ /* Freeze the unit */
+ int (*freeze)(Unit *u);
+ int (*thaw)(Unit *u);
+ bool (*can_freeze)(Unit *u);
+
/* Return which kind of data can be cleaned */
int (*can_clean)(Unit *u, ExecCleanMask *ret);
void (*notify_cgroup_oom)(Unit *u);
/* Called whenever a process of this unit sends us a message */
- void (*notify_message)(Unit *u, const struct ucred *ucred, char **tags, FDSet *fds);
+ void (*notify_message)(Unit *u, const struct ucred *ucred, char * const *tags, FDSet *fds);
/* Called whenever a name this Unit registered for comes or goes away. */
void (*bus_name_owner_change)(Unit *u, const char *new_owner);
* of this type will immediately fail. */
bool (*supported)(void);
- /* The bus vtable */
- const sd_bus_vtable *bus_vtable;
-
/* The strings to print in status messages */
UnitStatusMessageFormats status_message_formats;
/* True if the unit type knows a failure state, and thus can be source of an OnFailure= dependency */
bool can_fail:1;
- /* True if After= dependencies should be refused */
- bool refuse_after:1;
-
/* True if units of this type shall be startable only once and then never again */
bool once_only:1;
bool unit_has_name(const Unit *u, const char *name);
UnitActiveState unit_active_state(Unit *u);
+FreezerState unit_freezer_state(Unit *u);
+int unit_freezer_state_kernel(Unit *u, FreezerState *ret);
const char* unit_sub_state_to_string(Unit *u);
int unit_clean(Unit *u, ExecCleanMask mask);
int unit_can_clean(Unit *u, ExecCleanMask *ret_mask);
+bool unit_can_freeze(Unit *u);
+int unit_freeze(Unit *u);
+void unit_frozen(Unit *u);
+
+int unit_thaw(Unit *u);
+void unit_thawed(Unit *u);
+
+int unit_freeze_vtable_common(Unit *u);
+int unit_thaw_vtable_common(Unit *u);
+
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
goto fail;
}
-#if HAVE_XZ || HAVE_LZ4
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
/* If we will remove the coredump anyway, do not compress. */
if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
log_debug("Processing coredump received on stdin...");
for (;;) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
struct msghdr mh = {
.msg_control = &control,
.msg_controllen = sizeof(control),
mh.msg_iov = &iovec;
- n = recvmsg(fd, &mh, MSG_CMSG_CLOEXEC);
+ n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
if (n < 0) {
free(iovec.iov_base);
- r = log_error_errno(errno, "Failed to receive datagram: %m");
+ r = log_error_errno(n, "Failed to receive datagram: %m");
goto finish;
}
/* The final zero-length datagram carries the file descriptor and tells us
* that we're done. */
if (n == 0) {
- struct cmsghdr *cmsg, *found = NULL;
+ struct cmsghdr *found;
free(iovec.iov_base);
- CMSG_FOREACH(cmsg, &mh) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
- assert(!found);
- found = cmsg;
- }
- }
-
+ found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
if (!found) {
- log_error("Coredump file descriptor missing.");
- r = -EBADMSG;
+ cmsg_close_all(&mh);
+ r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+ "Coredump file descriptor missing.");
goto finish;
}
assert(input_fd < 0);
input_fd = *(int*) CMSG_DATA(found);
break;
- }
+ } else
+ cmsg_close_all(&mh);
/* Add trailing NUL byte, in case these are strings */
((char*) iovec.iov_base)[n] = 0;
r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
if (r < 0)
goto finish;
-
- cmsg_close_all(&mh);
}
/* Make sure we got all data we really need */
break;
case ARG_FILE:
- r = glob_extend(&arg_file, optarg);
+ r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
break;
if (access(filename, R_OK) < 0)
return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
- if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
+ if (path && !ENDSWITH_SET(filename, ".xz", ".lz4", ".zst")) {
*path = TAKE_PTR(filename);
return 0;
}
if (filename) {
-#if HAVE_XZ || HAVE_LZ4
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
_cleanup_close_ int fdf;
fdf = open(filename, O_RDONLY | O_CLOEXEC);
/* None, nothing to do */
return 0;
- if (PATH_IN_SET(device_path, "/dev/urandom", "/dev/random", "/dev/hw_random")) {
+ if (PATH_IN_SET(device_path,
+ "/dev/urandom",
+ "/dev/random",
+ "/dev/hw_random",
+ "/dev/hwrng")) {
/* RNG device, add random dep */
fputs("After=systemd-random-seed.service\n", f);
return 0;
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- fprintf(f, "After=%1$s\nRequires=%1$s\n", unit);
+ fprintf(f,
+ "After=%1$s\n"
+ "Requires=%1$s\n", unit);
} else {
/* Regular file, add mount dependency */
_cleanup_free_ char *escaped_path = specifier_escape(device_path);
if (tmp)
fprintf(f,
- "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
+ "ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs ext2 '/dev/mapper/%s'\n",
name_escaped);
if (swap)
fprintf(f,
- "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
+ "ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs swap '/dev/mapper/%s'\n",
name_escaped);
if (keydev)
#include "alloc-util.h"
#include "ask-password-api.h"
#include "cryptsetup-pkcs11.h"
+#include "cryptsetup-util.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
#include "stat-util.h"
#include "strv.h"
-#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
-
-static int load_key_file(
- const char *key_file,
- size_t key_file_size,
- uint64_t key_file_offset,
- void **ret_encrypted_key,
- size_t *ret_encrypted_key_size) {
-
- _cleanup_(erase_and_freep) char *buffer = NULL;
- _cleanup_close_ int fd = -1;
- ssize_t n;
- int r;
-
- assert(key_file);
- assert(ret_encrypted_key);
- assert(ret_encrypted_key_size);
-
- fd = open(key_file, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return log_error_errno(errno, "Failed to load encrypted PKCS#11 key: %m");
-
- if (key_file_size == 0) {
- struct stat st;
-
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "Failed to stat key file: %m");
-
- r = stat_verify_regular(&st);
- if (r < 0)
- return log_error_errno(r, "Key file is not a regular file: %m");
-
- if (st.st_size == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
- if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
- char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
- return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
- "Key file larger (%s) than allowed maximum size (%s), refusing.",
- format_bytes(buf1, sizeof(buf1), st.st_size),
- format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
- }
-
- if (key_file_offset >= (uint64_t) st.st_size)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
-
- key_file_size = st.st_size - key_file_offset;
- }
-
- buffer = malloc(key_file_size);
- if (!buffer)
- return log_oom();
-
- if (key_file_offset > 0)
- n = pread(fd, buffer, key_file_size, key_file_offset);
- else
- n = read(fd, buffer, key_file_size);
- if (n < 0)
- return log_error_errno(errno, "Failed to read PKCS#11 key file: %m");
- if (n == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
-
- *ret_encrypted_key = TAKE_PTR(buffer);
- *ret_encrypted_key_size = (size_t) n;
-
- return 0;
-}
-
struct pkcs11_callback_data {
const char *friendly_name;
usec_t until;
size_t encrypted_key_size;
void *decrypted_key;
size_t decrypted_key_size;
+ bool free_encrypted_key;
};
static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) {
free(data->decrypted_key);
- free(data->encrypted_key);
+
+ if (data->free_encrypted_key)
+ free(data->encrypted_key);
}
static int pkcs11_callback(
int decrypt_pkcs11_key(
const char *friendly_name,
const char *pkcs11_uri,
- const char *key_file,
+ const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
size_t key_file_size,
uint64_t key_file_offset,
+ const void *key_data, /* … or key_data and key_data_size (for literal keys) */
+ size_t key_data_size,
usec_t until,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
assert(friendly_name);
assert(pkcs11_uri);
- assert(key_file);
+ assert(key_file || key_data);
assert(ret_decrypted_key);
assert(ret_decrypted_key_size);
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
- r = load_key_file(key_file, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
- if (r < 0)
- return r;
+ if (key_data) {
+ data.encrypted_key = (void*) key_data;
+ data.encrypted_key_size = key_data_size;
+
+ data.free_encrypted_key = false;
+ } else {
+ r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
+ if (r < 0)
+ return r;
+
+ data.free_encrypted_key = true;
+ }
r = pkcs11_find_token(pkcs11_uri, pkcs11_callback, &data);
if (r < 0)
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
+ const void *key_data,
+ size_t key_data_size,
usec_t until,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size);
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
+ const void *key_data,
+ size_t key_data_size,
usec_t until,
void **ret_decrypted_key,
size_t *ret_decrypted_key_size) {
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "cryptsetup-util.h"
+#include "fd-util.h"
+#include "format-util.h"
+#include "memory-util.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "strv.h"
+
+#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
+
+int load_key_file(
+ const char *key_file,
+ char **search_path,
+ size_t key_file_size,
+ uint64_t key_file_offset,
+ void **ret_key,
+ size_t *ret_key_size) {
+
+ _cleanup_(erase_and_freep) char *buffer = NULL;
+ _cleanup_free_ char *discovered_path = NULL;
+ _cleanup_close_ int fd = -1;
+ ssize_t n;
+ int r;
+
+ assert(key_file);
+ assert(ret_key);
+ assert(ret_key_size);
+
+ if (strv_isempty(search_path) || path_is_absolute(key_file)) {
+ fd = open(key_file, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
+ } else {
+ char **i;
+
+ STRV_FOREACH(i, search_path) {
+ _cleanup_free_ char *joined;
+
+ joined = path_join(*i, key_file);
+ if (!joined)
+ return log_oom();
+
+ fd = open(joined, O_RDONLY|O_CLOEXEC);
+ if (fd >= 0) {
+ discovered_path = TAKE_PTR(joined);
+ break;
+ }
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
+ }
+
+ if (!discovered_path) {
+ /* Search path supplied, but file not found, report by returning NULL, but not failing */
+ *ret_key = NULL;
+ *ret_key_size = 0;
+ return 0;
+ }
+
+ assert(fd >= 0);
+ key_file = discovered_path;
+ }
+
+ if (key_file_size == 0) {
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
+
+ r = stat_verify_regular(&st);
+ if (r < 0)
+ return log_error_errno(r, "Key file is not a regular file: %m");
+
+ if (st.st_size == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
+ if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
+ char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
+ return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
+ "Key file larger (%s) than allowed maximum size (%s), refusing.",
+ format_bytes(buf1, sizeof(buf1), st.st_size),
+ format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
+ }
+
+ if (key_file_offset >= (uint64_t) st.st_size)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
+
+ key_file_size = st.st_size - key_file_offset;
+ }
+
+ buffer = malloc(key_file_size);
+ if (!buffer)
+ return log_oom();
+
+ if (key_file_offset > 0)
+ n = pread(fd, buffer, key_file_size, key_file_offset);
+ else
+ n = read(fd, buffer, key_file_size);
+ if (n < 0)
+ return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
+ if (n == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
+
+ *ret_key = TAKE_PTR(buffer);
+ *ret_key_size = (size_t) n;
+
+ return 1;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+int load_key_file(
+ const char *key_file,
+ char **search_path,
+ size_t key_file_size,
+ uint64_t key_file_offset,
+ void **ret_key,
+ size_t *ret_key_size);
#include "ask-password-api.h"
#include "crypt-util.h"
#include "cryptsetup-pkcs11.h"
+#include "cryptsetup-util.h"
#include "device-util.h"
#include "escape.h"
#include "fileio.h"
+#include "fs-util.h"
#include "fstab-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "main-func.h"
+#include "memory-util.h"
#include "mount-util.h"
#include "nulstr-util.h"
#include "parse-util.h"
static int arg_key_slot = CRYPT_ANY_SLOT;
static unsigned arg_keyfile_size = 0;
static uint64_t arg_keyfile_offset = 0;
+static bool arg_keyfile_erase = false;
+static bool arg_try_empty_password = false;
static char *arg_hash = NULL;
static char *arg_header = NULL;
static unsigned arg_tries = 3;
/* Options Debian's crypttab knows we don't:
- precheck=
check=
checkargs=
- noearly=
- loud=
+ noearly
+ loud
+ quiet
keyscript=
+ tmp= (the version without argument is supported)
+ initramfs
*/
static int parse_one_option(const char *option) {
return 0;
}
- } else if ((val = startswith(option, "key-slot="))) {
+ } else if ((val = startswith(option, "key-slot=")) ||
+ (val = startswith(option, "keyslot="))) {
arg_type = ANY_LUKS;
r = safe_atoi(val, &arg_key_slot);
return 0;
}
- } else if ((val = startswith(option, "hash="))) {
+ } else if ((val = startswith(option, "keyfile-erase="))) {
+
+ r = parse_boolean(val);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
+ return 0;
+ }
+
+ arg_keyfile_erase = r;
+
+ } else if (streq(option, "keyfile-erase"))
+ arg_keyfile_erase = true;
+
+ else if ((val = startswith(option, "hash="))) {
r = free_and_strdup(&arg_hash, val);
if (r < 0)
return log_oom();
arg_type = ANY_LUKS;
else if (streq(option, "tcrypt"))
arg_type = CRYPT_TCRYPT;
- else if (streq(option, "tcrypt-hidden")) {
+ else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_hidden = true;
} else if (streq(option, "tcrypt-system")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_system = true;
- } else if (streq(option, "tcrypt-veracrypt")) {
+ } else if (STR_IN_SET(option, "tcrypt-veracrypt", "veracrypt")) {
arg_type = CRYPT_TCRYPT;
arg_tcrypt_veracrypt = true;
} else if (STR_IN_SET(option, "plain", "swap", "tmp"))
if (r < 0)
return log_oom();
- } else if (!streq(option, "x-initrd.attach"))
+ } else if ((val = startswith(option, "try-empty-password="))) {
+
+ r = parse_boolean(val);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
+ return 0;
+ }
+
+ arg_try_empty_password = r;
+
+ } else if (streq(option, "try-empty-password"))
+ arg_try_empty_password = true;
+
+ else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
return 0;
struct crypt_device *cd,
const char *name,
const char *key_file,
+ const void *key_data,
+ size_t key_data_size,
char **passwords,
uint32_t flags) {
assert(cd);
assert(name);
- assert(key_file || (passwords && passwords[0]));
+ assert(key_file || key_data || !strv_isempty(passwords));
if (arg_pkcs11_uri)
/* Ask for a regular password */
if (arg_tcrypt_veracrypt)
params.flags |= CRYPT_TCRYPT_VERA_MODES;
- if (key_file) {
- r = read_one_line_file(key_file, &passphrase);
- if (r < 0) {
- log_error_errno(r, "Failed to read password file '%s': %m", key_file);
- return -EAGAIN; /* log with the actual error, but return EAGAIN */
- }
+ if (key_data) {
+ params.passphrase = key_data;
+ params.passphrase_size = key_data_size;
+ } else {
+ if (key_file) {
+ r = read_one_line_file(key_file, &passphrase);
+ if (r < 0) {
+ log_error_errno(r, "Failed to read password file '%s': %m", key_file);
+ return -EAGAIN; /* log with the actual error, but return EAGAIN */
+ }
- params.passphrase = passphrase;
- } else
- params.passphrase = passwords[0];
- params.passphrase_size = strlen(params.passphrase);
+ params.passphrase = passphrase;
+ } else
+ params.passphrase = passwords[0];
+
+ params.passphrase_size = strlen(params.passphrase);
+ }
r = crypt_load(cd, CRYPT_TCRYPT, ¶ms);
if (r < 0) {
- if (key_file && r == -EPERM) {
- log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
+ if (r == -EPERM) {
+ if (key_data)
+ log_error_errno(r, "Failed to activate using discovered key. (Key not correct?)");
+
+ if (key_file)
+ log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
+
return -EAGAIN; /* log the actual error, but return EAGAIN */
}
struct crypt_device *cd,
const char *name,
const char *key_file,
+ const void *key_data,
+ size_t key_data_size,
char **passwords,
uint32_t flags,
usec_t until) {
_cleanup_free_ char *friendly = NULL;
size_t decrypted_key_size = 0;
- if (!key_file)
+ if (!key_file && !key_data)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
friendly = friendly_disk_name(crypt_get_device_name(cd), name);
r = decrypt_pkcs11_key(
friendly,
arg_pkcs11_uri,
- key_file,
- arg_keyfile_size, arg_keyfile_offset,
+ key_file, arg_keyfile_size, arg_keyfile_offset,
+ key_data, key_data_size,
until,
&decrypted_key, &decrypted_key_size);
if (r >= 0)
return log_error_errno(r, "Failed to start device monitor: %m");
log_notice("Security token %s not present for unlocking volume %s, please plug it in.",
- arg_pkcs11_uri, friendly);
+ arg_pkcs11_uri, friendly);
/* Let's immediately rescan in case the token appeared in the time we needed
* to create and configure the monitor */
if (r < 0)
return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m");
+ } else if (key_data) {
+ if (pass_volume_key)
+ r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags);
+ else
+ r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags);
+ if (r == -EPERM) {
+ log_error_errno(r, "Failed to activate. (Key incorrect?)");
+ return -EAGAIN; /* Log actual error, but return EAGAIN */
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to activate: %m");
+
} else if (key_file) {
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
if (r == -EPERM) {
return flags;
}
+static void remove_and_erasep(const char **p) {
+ int r;
+
+ if (!*p)
+ return;
+
+ r = unlinkat_deallocate(AT_FDCWD, *p, UNLINK_ERASE);
+ if (r < 0 && r != -ENOENT)
+ log_warning_errno(r, "Unable to erase key file '%s', ignoring: %m", *p);
+}
+
static int run(int argc, char *argv[]) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
unsigned tries;
usec_t until;
crypt_status_info status;
+ _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
const char *key_file = NULL;
+ _cleanup_(erase_and_freep) void *key_data = NULL;
+ size_t key_data_size = 0;
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
if (argc < 4)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
+ if (!filename_is_valid(argv[2]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
+
if (argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none")) {
if (path_is_absolute(argv[4]))
key_file = argv[4];
/* A delicious drop of snake oil */
(void) mlockall(MCL_FUTURE);
+ if (!key_file) {
+ const char *fn;
+
+ /* If a key file is not explicitly specified, search for a key in a well defined
+ * search path, and load it. */
+
+ fn = strjoina(argv[2], ".key");
+ r = load_key_file(fn,
+ STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
+ 0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
+ &key_data, &key_data_size);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ log_debug("Automatically discovered key for volume '%s'.", argv[2]);
+ } else if (arg_keyfile_erase)
+ destroy_key_file = key_file; /* let's get this baby erased when we leave */
+
if (arg_header) {
log_debug("LUKS header: %s", arg_header);
r = crypt_init(&cd, arg_header);
}
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
- if (!key_file) {
+ if (!key_file && !key_data) {
r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags);
if (r >= 0) {
log_debug("Volume %s activated with LUKS token id %i.", argv[2], r);
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL;
- if (!key_file && !arg_pkcs11_uri) {
- r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
- if (r == -EAGAIN)
- continue;
- if (r < 0)
- return r;
+ /* When we were able to acquire multiple keys, let's always process them in this order:
+ *
+ * 1. A key acquired via PKCS#11 token
+ * 2. The discovered key: i.e. key_data + key_data_size
+ * 3. The configured key: i.e. key_file + arg_keyfile_offset + arg_keyfile_size
+ * 4. The empty password, in case arg_try_empty_password is set
+ * 5. We enquire the user for a password
+ */
+
+ if (!key_file && !key_data && !arg_pkcs11_uri) {
+
+ if (arg_try_empty_password) {
+ /* Hmm, let's try an empty password now, but only once */
+ arg_try_empty_password = false;
+
+ key_data = strdup("");
+ if (!key_data)
+ return log_oom();
+
+ key_data_size = 0;
+ } else {
+ /* Ask the user for a passphrase only as last resort, if we have
+ * nothing else to check for */
+
+ r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
+ if (r == -EAGAIN)
+ continue;
+ if (r < 0)
+ return r;
+ }
}
if (streq_ptr(arg_type, CRYPT_TCRYPT))
- r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
+ r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags);
else
- r = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags, until);
+ r = attach_luks_or_plain(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until);
if (r >= 0)
break;
if (r != -EAGAIN)
return r;
- /* Passphrase not correct? Let's try again! */
+ /* Key not correct? Let's try again! */
+
key_file = NULL;
- arg_pkcs11_uri = NULL;
+ key_data = erase_and_free(key_data);
+ key_data_size = 0;
+ arg_pkcs11_uri = mfree(arg_pkcs11_uri);
}
if (arg_tries != 0 && tries >= arg_tries)
} else if (streq(argv[1], "detach")) {
+ if (!filename_is_valid(argv[2]))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]);
+
r = crypt_init_by_name(&cd, argv[2]);
if (r == -ENODEV) {
log_info("Volume %s already inactive.", argv[2]);
}
}
+static bool locale_is_ok(const char *name) {
+
+ if (arg_root)
+ return locale_is_valid(name);
+
+ return locale_is_installed(name) > 0;
+}
+
static int prompt_locale(void) {
_cleanup_strv_free_ char **locales = NULL;
int r;
print_welcome();
r = prompt_loop("Please enter system locale name or number",
- locales, 60, locale_is_valid, &arg_locale);
+ locales, 60, locale_is_ok, &arg_locale);
if (r < 0)
return r;
return 0;
r = prompt_loop("Please enter system message locale name or number",
- locales, 60, locale_is_valid, &arg_locale_messages);
+ locales, 60, locale_is_ok, &arg_locale_messages);
if (r < 0)
return r;
" --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
" --keymap=KEYMAP Set keymap\n"
" --timezone=TIMEZONE Set timezone\n"
- " --hostname=NAME Set host name\n"
+ " --hostname=NAME Set hostname\n"
" --machine-ID=ID Set machine ID\n"
" --root-password=PASSWORD Set root password\n"
" --root-password-file=FILE Set root password from file\n"
break;
case ARG_LOCALE:
- if (!locale_is_valid(optarg))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Locale %s is not valid.", optarg);
-
r = free_and_strdup(&arg_locale, optarg);
if (r < 0)
return log_oom();
break;
case ARG_LOCALE_MESSAGES:
- if (!locale_is_valid(optarg))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Locale %s is not valid.", optarg);
-
r = free_and_strdup(&arg_locale_messages, optarg);
if (r < 0)
return log_oom();
assert_not_reached("Unhandled option");
}
+ /* We check if the specified locale strings are valid down here, so that we can take --root= into
+ * account when looking for the locale files. */
+
+ if (arg_locale && !locale_is_ok(arg_locale))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
+ if (arg_locale_messages && !locale_is_ok(arg_locale_messages))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
+
return 1;
}
AUTOMOUNT = 1 << 2,
MAKEFS = 1 << 3,
GROWFS = 1 << 4,
+ RWONLY = 1 << 5,
} MountpointFlags;
static const char *arg_dest = NULL;
"SourcePath=%s\n",
source);
- /* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, it's not
- * technically part of the basic initrd filesystem itself, and so shouldn't inherit the default
- * Before=local-fs.target dependency. */
- if (in_initrd() && path_startswith(where, "/sysroot"))
- fprintf(f, "DefaultDependencies=no\n");
-
if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
/* The default retry timeout that mount.nfs uses for 'bg' mounts
SET_FLAG(flags, NOFAIL, true);
}
- if (!(flags & NOFAIL) && !(flags & AUTOMOUNT))
- fprintf(f, "Before=%s\n", post);
-
if (!(flags & AUTOMOUNT) && opts) {
r = write_after(f, opts);
if (r < 0)
if (r < 0)
return r;
+ if (flags & RWONLY)
+ fprintf(f, "ReadWriteOnly=yes\n");
+
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", name);
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- fprintf(f, "Before=%s\n", post);
-
if (opts) {
r = write_after(f, opts);
if (r < 0)
while ((me = getmntent(f))) {
_cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
- bool makefs, growfs, noauto, nofail;
+ bool makefs, growfs, noauto, nofail, rwonly;
int k;
if (initrd && !mount_in_initrd(me))
makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
+ rwonly = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
me->mnt_type,
me->mnt_opts,
me->mnt_passno,
- makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
+ makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT | rwonly*RWONLY,
post,
fstab);
}
"/var",
NULL,
"tmpfs",
- "mode=0755",
+ "mode=0755" TMPFS_LIMITS_VAR,
0,
0,
SPECIAL_LOCAL_FS_TARGET,
path_is_absolute(path);
}
+bool supported_fstype(const char *fstype) {
+ /* Limit the set of supported file systems a bit, as protection against little tested kernel file
+ * systems. Also, we only support the resize ioctls for these file systems. */
+ return STR_IN_SET(fstype, "ext4", "btrfs", "xfs");
+}
+
int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm) {
_cleanup_free_ char *user_name = NULL, *realm = NULL;
const char *c;
if (r < 0)
return r;
+ (void) sd_bus_message_sensitive(m);
+
return sd_bus_message_append(m, "s", formatted);
}
int suitable_realm(const char *realm);
int suitable_image_path(const char *path);
+bool supported_fstype(const char *fstype);
+
int split_user_name_realm(const char *t, char **ret_user_name, char **ret_realm);
int bus_message_append_secret(sd_bus_message *m, UserRecord *secret);
EXPORT_FORMAT_MINIMAL, /* also strip signature */
} arg_export_format = EXPORT_FORMAT_FULL;
-static const BusLocator home_mgr = {
- .destination = "org.freedesktop.home1",
- .path = "/org/freedesktop/home1",
- .interface = "org.freedesktop.home1.Manager",
-};
-
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra, json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_this_machine, json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_privileged, json_variant_unrefp);
if (r < 0)
return r;
- r = bus_call_method(bus, &home_mgr, "ListHomes", &error, &reply, NULL);
+ r = bus_call_method(bus, bus_home_mgr, "ListHomes", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list homes: %s", bus_error_message(&error, r));
if (arg_legend && !arg_json) {
if (table_get_rows(table) > 1)
- printf("\n%zu homes listed.\n", table_get_rows(table) - 1);
+ printf("\n%zu home areas listed.\n", table_get_rows(table) - 1);
else
- printf("No homes.\n");
+ printf("No home areas.\n");
}
return 0;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ActivateHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ActivateHome");
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "DeactivateHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "DeactivateHome");
if (r < 0)
return bus_log_create_error(r);
continue;
}
- r = bus_call_method(bus, &home_mgr, "GetUserRecordByName", &error, &reply, "s", *i);
+ r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", *i);
} else
- r = bus_call_method(bus, &home_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
+ r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
if (r < 0) {
log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "AuthenticateHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "AuthenticateHome");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return r;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "CreateHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "CreateHome");
if (r < 0)
return bus_log_create_error(r);
+ (void) sd_bus_message_sensitive(m);
+
r = sd_bus_message_append(m, "s", formatted);
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "RemoveHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "RemoveHome");
if (r < 0)
return bus_log_create_error(r);
if (!identity_properties_specified())
return log_error_errno(SYNTHETIC_ERRNO(EALREADY), "No field to change specified.");
- r = bus_call_method(bus, &home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
+ r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
if (r < 0)
return log_error_errno(r, "Failed to acquire user home record: %s", bus_error_message(&error, r));
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ char *formatted = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "UpdateHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "UpdateHome");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return r;
+ (void) sd_bus_message_sensitive(m);
+
r = sd_bus_message_append(m, "s", formatted);
if (r < 0)
return bus_log_create_error(r);
log_debug("Resizing");
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ResizeHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ResizeHome");
if (r < 0)
return bus_log_create_error(r);
log_debug("Propagating password");
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ChangePasswordHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome");
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ChangePasswordHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome");
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ResizeHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ResizeHome");
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "LockHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "LockHome");
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "UnlockHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "UnlockHome");
if (r < 0)
return bus_log_create_error(r);
return log_oom();
for (;;) {
- r = bus_message_new_method_call(bus, &m, &home_mgr, "AcquireHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "AcquireHome");
if (r < 0)
return bus_log_create_error(r);
}
}
- r = bus_call_method(bus, &home_mgr, "GetHomeByName", &error, &reply, "s", argv[1]);
+ r = bus_call_method(bus, bus_home_mgr, "GetHomeByName", &error, &reply, "s", argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
/* Close the fd that pings the home now. */
acquired_fd = safe_close(acquired_fd);
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ReleaseHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ReleaseHome");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return r;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "LockAllHomes");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "LockAllHomes");
if (r < 0)
return bus_log_create_error(r);
printf("%1$s [OPTIONS...] COMMAND ...\n\n"
"%2$sCreate, manipulate or inspect home directories.%3$s\n"
"\n%4$sCommands:%5$s\n"
- " list List homes\n"
- " activate USER… Activate home\n"
- " deactivate USER… Deactivate home\n"
- " inspect USER… Inspect home\n"
- " authenticate USER… Authenticate home\n"
+ " list List home areas\n"
+ " activate USER… Activate a home area\n"
+ " deactivate USER… Deactivate a home area\n"
+ " inspect USER… Inspect a home area\n"
+ " authenticate USER… Authenticate a home area\n"
" create USER Create a home area\n"
" remove USER… Remove a home area\n"
" update USER Update a home area\n"
" passwd USER Change password of a home area\n"
" resize USER SIZE Resize a home area\n"
- " lock USER… Temporarily lock an active home\n"
- " unlock USER… Unlock a temporarily locked home\n"
- " lock-all Lock all suitable homes\n"
- " with USER [COMMAND…] Run shell or command with access to home\n"
+ " lock USER… Temporarily lock an active home area\n"
+ " unlock USER… Unlock a temporarily locked home area\n"
+ " lock-all Lock all suitable home areas\n"
+ " with USER [COMMAND…] Run shell or command with access to a home area\n"
"\n%4$sOptions:%5$s\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --fs-type=TYPE File system type to use in case of luks\n"
" storage (ext4, xfs, btrfs)\n"
" --luks-discard=BOOL Whether to use 'discard' feature of file system\n"
+ " when activated (mounted)\n"
+ " --luks-offline-discard=BOOL\n"
+ " Whether to trim file on logout\n"
" --luks-cipher=CIPHER Cipher to use for LUKS encryption\n"
" --luks-cipher-mode=MODE Cipher mode to use for LUKS encryption\n"
" --luks-volume-key-size=BITS\n"
"\n%4$sCIFS User Record Properties:%5$s\n"
" --cifs-domain=DOMAIN CIFS (Windows) domain\n"
" --cifs-user-name=USER CIFS (Windows) user name\n"
- " --cifs-service=SERVICE CIFS (Windows) service to mount as home\n"
+ " --cifs-service=SERVICE CIFS (Windows) service to mount as home area\n"
"\n%4$sLogin Behaviour User Record Properties:%5$s\n"
" --stop-delay=SECS How long to leave user services running after\n"
" logout\n"
ARG_IMAGE_PATH,
ARG_UMASK,
ARG_LUKS_DISCARD,
+ ARG_LUKS_OFFLINE_DISCARD,
ARG_JSON,
ARG_SETENV,
ARG_TIMEZONE,
{ "image-path", required_argument, NULL, ARG_IMAGE_PATH },
{ "fs-type", required_argument, NULL, ARG_FS_TYPE },
{ "luks-discard", required_argument, NULL, ARG_LUKS_DISCARD },
+ { "luks-offline-discard", required_argument, NULL, ARG_LUKS_OFFLINE_DISCARD },
{ "luks-cipher", required_argument, NULL, ARG_LUKS_CIPHER },
{ "luks-cipher-mode", required_argument, NULL, ARG_LUKS_CIPHER_MODE },
{ "luks-volume-key-size", required_argument, NULL, ARG_LUKS_VOLUME_KEY_SIZE },
if (!locale_is_valid(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale '%s' is not valid.", optarg);
+ if (locale_is_installed(optarg) <= 0)
+ log_warning("Locale '%s' is not installed, accepting anyway.", optarg);
+
r = json_variant_set_field_string(&arg_identity_extra, "preferredLanguage", optarg);
if (r < 0)
return log_error_errno(r, "Failed to set preferredLanguage field: %m");
break;
+ case ARG_LUKS_OFFLINE_DISCARD:
+ if (isempty(optarg)) {
+ r = drop_from_identity("luksOfflineDiscard");
+ if (r < 0)
+ return r;
+
+ break;
+ }
+
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --luks-offline-discard= parameter: %s", optarg);
+
+ r = json_variant_set_field_boolean(&arg_identity_extra, "luksOfflineDiscard", r);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set offline discard field: %m");
+
+ break;
+
case ARG_LUKS_VOLUME_KEY_SIZE:
case ARG_LUKS_PBKDF_PARALLEL_THREADS:
case ARG_RATE_LIMIT_BURST: {
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "conf-parser.h"
+#include "def.h"
+#include "home-util.h"
+#include "homed-conf.h"
+
+int manager_parse_config_file(Manager *m) {
+ int r;
+
+ assert(m);
+
+ r = config_parse_many_nulstr(PKGSYSCONFDIR "/homed.conf",
+ CONF_PATHS_NULSTR("systemd/homed.conf.d"),
+ "Home\0",
+ config_item_perf_lookup, homed_gperf_lookup,
+ CONFIG_PARSE_WARN, m);
+ if (r < 0)
+ return r;
+
+ return 0;
+
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_default_storage, user_storage, UserStorage, "Failed to parse default storage setting");
+
+int config_parse_default_file_system_type(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char **s = data;
+
+ assert(rvalue);
+ assert(s);
+
+ if (!isempty(rvalue) && !supported_fstype(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unsupported file system, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return free_and_strdup_warn(s, empty_to_null(rvalue));
+
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "conf-parser.h"
+#include "homed-manager.h"
+
+int manager_parse_config_file(Manager *m);
+
+const struct ConfigPerfItem* homed_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_default_storage);
+CONFIG_PARSER_PROTOTYPE(config_parse_default_file_system_type);
--- /dev/null
+%{
+#if __GNUC__ >= 7
+_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
+#endif
+#include <stddef.h>
+#include "conf-parser.h"
+#include "homed-conf.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name homed_gperf_hash
+%define lookup-function-name homed_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Home.DefaultStorage, config_parse_default_storage, 0, offsetof(Manager, default_storage)
+Home.DefaultFileSystemType, config_parse_default_file_system_type, 0, offsetof(Manager, default_file_system_type)
/* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
-const sd_bus_vtable home_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("UserName", "s", NULL, offsetof(Home, user_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Home, uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("UnixRecord", "(suusss)", property_get_unix_record, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
- SD_BUS_PROPERTY("UserRecord", "(sb)", property_get_user_record, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Activate", "s", NULL, bus_home_method_activate, SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
- SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Realize", "s", NULL, bus_home_method_realize, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Fixate", "s", NULL, bus_home_method_fixate, SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Authenticate", "s", NULL, bus_home_method_authenticate, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Update", "s", NULL, bus_home_method_update, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Resize", "ts", NULL, bus_home_method_resize, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("ChangePassword", "ss", NULL, bus_home_method_change_password, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
- SD_BUS_METHOD("Unlock", "s", NULL, bus_home_method_unlock, SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Acquire", "sb", "h", bus_home_method_acquire, SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("Ref", "b", "h", bus_home_method_ref, 0),
- SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
- SD_BUS_VTABLE_END
-};
-
int bus_home_path(Home *h, char **ret) {
assert(ret);
return sd_bus_path_encode("/org/freedesktop/home1/home", h->user_name, ret);
}
-int bus_home_object_find(
+static int bus_home_object_find(
sd_bus *bus,
const char *path,
const char *interface,
return 1;
}
-int bus_home_node_enumerator(
+static int bus_home_node_enumerator(
sd_bus *bus,
const char *path,
void *userdata,
return 1;
}
+const sd_bus_vtable home_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+
+ SD_BUS_PROPERTY("UserName", "s",
+ NULL, offsetof(Home, user_name),
+ SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("UID", "u",
+ NULL, offsetof(Home, uid),
+ SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("UnixRecord", "(suusss)",
+ property_get_unix_record, 0,
+ SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("State", "s",
+ property_get_state, 0,
+ 0),
+ SD_BUS_PROPERTY("UserRecord", "(sb)",
+ property_get_user_record, 0,
+ SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE),
+
+ SD_BUS_METHOD_WITH_NAMES("Activate",
+ "s",
+ SD_BUS_PARAM(secret),
+ NULL,,
+ bus_home_method_activate,
+ SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0),
+ SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("Realize",
+ "s",
+ SD_BUS_PARAM(secret),
+ NULL,,
+ bus_home_method_realize,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("Fixate",
+ "s",
+ SD_BUS_PARAM(secret),
+ NULL,,
+ bus_home_method_fixate,
+ SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("Authenticate",
+ "s",
+ SD_BUS_PARAM(secret),
+ NULL,,
+ bus_home_method_authenticate,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("Update",
+ "s",
+ SD_BUS_PARAM(user_record),
+ NULL,,
+ bus_home_method_update,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("Resize",
+ "ts",
+ SD_BUS_PARAM(size)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ bus_home_method_resize,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("ChangePassword",
+ "ss",
+ SD_BUS_PARAM(new_secret)
+ SD_BUS_PARAM(old_secret),
+ NULL,,
+ bus_home_method_change_password,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0),
+ SD_BUS_METHOD_WITH_NAMES("Unlock",
+ "s",
+ SD_BUS_PARAM(secret),
+ NULL,,
+ bus_home_method_unlock,
+ SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("Acquire",
+ "sb",
+ SD_BUS_PARAM(secret)
+ SD_BUS_PARAM(please_suspend),
+ "h",
+ SD_BUS_PARAM(send_fd),
+ bus_home_method_acquire,
+ SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("Ref",
+ "b",
+ SD_BUS_PARAM(please_suspend),
+ "h",
+ SD_BUS_PARAM(send_fd),
+ bus_home_method_ref,
+ 0),
+ SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation home_object = {
+ "/org/freedesktop/home1/home",
+ "org.freedesktop.home1.Home",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}),
+ .node_enumerator = bus_home_node_enumerator,
+ .manager = true,
+};
+
static int on_deferred_change(sd_event_source *s, void *userdata) {
_cleanup_free_ char *path = NULL;
Home *h = userdata;
#include "sd-bus.h"
+#include "bus-util.h"
#include "homed-home.h"
int bus_home_client_is_trusted(Home *h, sd_bus_message *message);
int bus_home_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
-extern const sd_bus_vtable home_vtable[];
+extern const BusObjectImplementation home_object;
int bus_home_path(Home *h, char **ret);
-int bus_home_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int bus_home_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-
int bus_home_emit_change(Home *h);
int bus_home_emit_remove(Home *h);
if (r < 0)
return r;
if (r == 0) {
+ const char *homework;
+
/* Child */
if (setenv("NOTIFY_SOCKET", "/run/systemd/home/notify", 1) < 0) {
_exit(EXIT_FAILURE);
}
+ if (h->manager->default_storage >= 0)
+ if (setenv("SYSTEMD_HOME_DEFAULT_STORAGE", user_storage_to_string(h->manager->default_storage), 1) < 0) {
+ log_error_errno(errno, "Failed to set $SYSTEMD_HOME_DEFAULT_STORAGE: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (h->manager->default_file_system_type)
+ if (setenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE", h->manager->default_file_system_type, 1) < 0) {
+ log_error_errno(errno, "Failed to set $SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE: %m");
+ _exit(EXIT_FAILURE);
+ }
+
r = rearrange_stdio(stdin_fd, stdout_fd, STDERR_FILENO);
if (r < 0) {
log_error_errno(r, "Failed to rearrange stdin/stdout/stderr: %m");
stdin_fd = stdout_fd = -1; /* have been invalidated by rearrange_stdio() */
- execl(SYSTEMD_HOMEWORK_PATH, SYSTEMD_HOMEWORK_PATH, verb, NULL);
+ /* Allow overriding the homework path via an environment variable, to make debugging
+ * easier. */
+ homework = getenv("SYSTEMD_HOMEWORK_PATH") ?: SYSTEMD_HOMEWORK_PATH;
+
+ execl(homework, homework, verb, NULL);
log_error_errno(errno, "Failed to invoke " SYSTEMD_HOMEWORK_PATH ": %m");
_exit(EXIT_FAILURE);
}
return sd_bus_reply_method_return(message, NULL);
}
-const sd_bus_vtable manager_vtable[] = {
+static const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("AutoLogin", "a(sso)", property_get_auto_login, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_METHOD("GetHomeByName", "s", "usussso", method_get_home_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetHomeByUID", "u", "ssussso", method_get_home_by_uid, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetUserRecordByName", "s", "sbo", method_get_user_record_by_name, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("GetUserRecordByUID", "u", "sbo", method_get_user_record_by_uid, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("ListHomes", NULL, "a(susussso)", method_list_homes, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("GetHomeByName",
+ "s",
+ SD_BUS_PARAM(user_name),
+ "usussso",
+ SD_BUS_PARAM(uid)
+ SD_BUS_PARAM(home_state)
+ SD_BUS_PARAM(gid)
+ SD_BUS_PARAM(real_name)
+ SD_BUS_PARAM(home_directory)
+ SD_BUS_PARAM(shell)
+ SD_BUS_PARAM(bus_path),
+ method_get_home_by_name,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("GetHomeByUID",
+ "u",
+ SD_BUS_PARAM(uid),
+ "ssussso",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(home_state)
+ SD_BUS_PARAM(gid)
+ SD_BUS_PARAM(real_name)
+ SD_BUS_PARAM(home_directory)
+ SD_BUS_PARAM(shell)
+ SD_BUS_PARAM(bus_path),
+ method_get_home_by_uid,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("GetUserRecordByName",
+ "s",
+ SD_BUS_PARAM(user_name),
+ "sbo",
+ SD_BUS_PARAM(user_record)
+ SD_BUS_PARAM(incomplete)
+ SD_BUS_PARAM(bus_path),
+ method_get_user_record_by_name,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("GetUserRecordByUID",
+ "u",
+ SD_BUS_PARAM(uid),
+ "sbo",
+ SD_BUS_PARAM(user_record)
+ SD_BUS_PARAM(incomplete)
+ SD_BUS_PARAM(bus_path),
+ method_get_user_record_by_uid,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("ListHomes",
+ NULL,,
+ "a(susussso)",
+ SD_BUS_PARAM(home_areas),
+ method_list_homes,
+ SD_BUS_VTABLE_UNPRIVILEGED),
/* The following methods directly execute an operation on a home area, without ref-counting, queueing
* or anything, and are accessible through homectl. */
- SD_BUS_METHOD("ActivateHome", "ss", NULL, method_activate_home, SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("DeactivateHome", "s", NULL, method_deactivate_home, 0),
- SD_BUS_METHOD("RegisterHome", "s", NULL, method_register_home, SD_BUS_VTABLE_UNPRIVILEGED), /* Add JSON record to homed, but don't create actual $HOME */
- SD_BUS_METHOD("UnregisterHome", "s", NULL, method_unregister_home, SD_BUS_VTABLE_UNPRIVILEGED), /* Remove JSON record from homed, but don't remove actual $HOME */
- SD_BUS_METHOD("CreateHome", "s", NULL, method_create_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Add JSON record, and create $HOME for it */
- SD_BUS_METHOD("RealizeHome", "ss", NULL, method_realize_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Create $HOME for already registered JSON entry */
- SD_BUS_METHOD("RemoveHome", "s", NULL, method_remove_home, SD_BUS_VTABLE_UNPRIVILEGED), /* Remove JSON record and remove $HOME */
- SD_BUS_METHOD("FixateHome", "ss", NULL, method_fixate_home, SD_BUS_VTABLE_SENSITIVE), /* Investigate $HOME and propagate contained JSON record into our database */
- SD_BUS_METHOD("AuthenticateHome", "ss", NULL, method_authenticate_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Just check credentials */
- SD_BUS_METHOD("UpdateHome", "s", NULL, method_update_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), /* Update JSON record of existing user */
- SD_BUS_METHOD("ResizeHome", "sts", NULL, method_resize_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("ChangePasswordHome", "sss", NULL, method_change_password_home, SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("LockHome", "s", NULL, method_lock_home, 0), /* Prepare active home for system suspend: flush out passwords, suspend access */
- SD_BUS_METHOD("UnlockHome", "ss", NULL, method_unlock_home, SD_BUS_VTABLE_SENSITIVE), /* Make $HOME usable after system resume again */
-
- /* The following methods implement ref-counted activation, and are what the PAM module calls (and
- * what "homectl with" runs). In contrast to the methods above which fail if an operation is already
- * being executed on a home directory, these ones will queue the request, and are thus more
- * reliable. Moreover, they are a bit smarter: AcquireHome() will fixate, activate, unlock, or
- * authenticate depending on the state of the home, so that the end result is always the same
- * (i.e. the home directory is accessible), and we always validate the specified passwords. RefHome()
- * will not authenticate, and thus only works if home is already active. */
- SD_BUS_METHOD("AcquireHome", "ssb", "h", method_acquire_home, SD_BUS_VTABLE_SENSITIVE),
- SD_BUS_METHOD("RefHome", "sb", "h", method_ref_home, 0),
- SD_BUS_METHOD("ReleaseHome", "s", NULL, method_release_home, 0),
+ SD_BUS_METHOD_WITH_NAMES("ActivateHome",
+ "ss",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ method_activate_home,
+ SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("DeactivateHome",
+ "s",
+ SD_BUS_PARAM(user_name),
+ NULL,,
+ method_deactivate_home,
+ 0),
+
+ /* Add the JSON record to homed, but don't create actual $HOME */
+ SD_BUS_METHOD_WITH_NAMES("RegisterHome",
+ "s",
+ SD_BUS_PARAM(user_record),
+ NULL,,
+ method_register_home,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ /* Remove the JSON record from homed, but don't remove actual $HOME */
+ SD_BUS_METHOD_WITH_NAMES("UnregisterHome",
+ "s",
+ SD_BUS_PARAM(user_name),
+ NULL,,
+ method_unregister_home,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ /* Add JSON record, and create $HOME for it */
+ SD_BUS_METHOD_WITH_NAMES("CreateHome",
+ "s",
+ SD_BUS_PARAM(user_record),
+ NULL,,
+ method_create_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ /* Create $HOME for already registered JSON entry */
+ SD_BUS_METHOD_WITH_NAMES("RealizeHome",
+ "ss",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ method_realize_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ /* Remove the JSON record and remove $HOME */
+ SD_BUS_METHOD_WITH_NAMES("RemoveHome",
+ "s",
+ SD_BUS_PARAM(user_name),
+ NULL,,
+ method_remove_home,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ /* Investigate $HOME and propagate contained JSON record into our database */
+ SD_BUS_METHOD_WITH_NAMES("FixateHome",
+ "ss",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ method_fixate_home,
+ SD_BUS_VTABLE_SENSITIVE),
+
+ /* Just check credentials */
+ SD_BUS_METHOD_WITH_NAMES("AuthenticateHome",
+ "ss",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ method_authenticate_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ /* Update the JSON record of existing user */
+ SD_BUS_METHOD_WITH_NAMES("UpdateHome",
+ "s",
+ SD_BUS_PARAM(user_record),
+ NULL,,
+ method_update_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ SD_BUS_METHOD_WITH_NAMES("ResizeHome",
+ "sts",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(size)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ method_resize_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ SD_BUS_METHOD_WITH_NAMES("ChangePasswordHome",
+ "sss",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(new_secret)
+ SD_BUS_PARAM(old_secret),
+ NULL,,
+ method_change_password_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+
+ /* Prepare active home for system suspend: flush out passwords, suspend access */
+ SD_BUS_METHOD_WITH_NAMES("LockHome",
+ "s",
+ SD_BUS_PARAM(user_name),
+ NULL,,
+ method_lock_home,
+ 0),
+
+ /* Make $HOME usable after system resume again */
+ SD_BUS_METHOD_WITH_NAMES("UnlockHome",
+ "ss",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(secret),
+ NULL,,
+ method_unlock_home,
+ SD_BUS_VTABLE_SENSITIVE),
+
+ /* The following methods implement ref-counted activation, and are what the PAM module and "homectl
+ * with" use. In contrast to the methods above which fail if an operation is already being executed
+ * on a home directory, these ones will queue the request, and are thus more reliable. Moreover,
+ * they are a bit smarter: AcquireHome() will fixate, activate, unlock, or authenticate depending on
+ * the state of the home area, so that the end result is always the same (i.e. the home directory is
+ * accessible), and we always validate the specified passwords. RefHome() will not authenticate, and
+ * thus only works if the home area is already active. */
+ SD_BUS_METHOD_WITH_NAMES("AcquireHome",
+ "ssb",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(secret)
+ SD_BUS_PARAM(please_suspend),
+ "h",
+ SD_BUS_PARAM(send_fd),
+ method_acquire_home,
+ SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE),
+ SD_BUS_METHOD_WITH_NAMES("RefHome",
+ "sb",
+ SD_BUS_PARAM(user_name)
+ SD_BUS_PARAM(please_suspend),
+ "h",
+ SD_BUS_PARAM(send_fd),
+ method_ref_home,
+ 0),
+ SD_BUS_METHOD_WITH_NAMES("ReleaseHome",
+ "s",
+ SD_BUS_PARAM(user_name),
+ NULL,,
+ method_release_home,
+ 0),
/* An operation that acts on all homes that allow it */
SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
SD_BUS_VTABLE_END
};
+const BusObjectImplementation manager_object = {
+ "/org/freedesktop/home1",
+ "org.freedesktop.home1.Manager",
+ .vtables = BUS_VTABLES(manager_vtable),
+ .children = BUS_IMPLEMENTATIONS(&home_object),
+};
+
static int on_deferred_auto_login(sd_event_source *s, void *userdata) {
Manager *m = userdata;
int r;
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include "sd-bus.h"
+#include "bus-util.h"
-extern const sd_bus_vtable manager_vtable[];
+extern const BusObjectImplementation manager_object;
#include "fs-util.h"
#include "gpt.h"
#include "home-util.h"
+#include "homed-conf.h"
#include "homed-home-bus.h"
#include "homed-home.h"
#include "homed-manager-bus.h"
assert(ret);
- m = new0(Manager, 1);
+ m = new(Manager, 1);
if (!m)
return -ENOMEM;
+ *m = (Manager) {
+ .default_storage = _USER_STORAGE_INVALID,
+ };
+
+ r = manager_parse_config_file(m);
+ if (r < 0)
+ return r;
+
r = sd_event_default(&m->event);
if (r < 0)
return r;
varlink_server_unref(m->varlink_server);
+ free(m->default_file_system_type);
+
return mfree(m);
}
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
- r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/home1", "org.freedesktop.home1.Manager", manager_vtable, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add manager object vtable: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/home1/home", "org.freedesktop.home1.Home", home_vtable, bus_home_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add image object vtable: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/home1/home", bus_home_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add image enumerator: %m");
-
- r = sd_bus_add_object_manager(m->bus, NULL, "/org/freedesktop/home1/home");
- if (r < 0)
- return log_error_errno(r, "Failed to add object manager: %m");
-
- r = bus_log_control_api_register(m->bus);
+ r = bus_add_implementation(m->bus, &manager_object, m);
if (r < 0)
return r;
return -ENOMEM;
if (ret_sender) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
bool found_ucred = false;
struct cmsghdr *cmsg;
struct msghdr mh;
.msg_controllen = sizeof(control),
};
- m = recvmsg(fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ m = recvmsg_safe(fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (m < 0)
- return -errno;
+ return m;
cmsg_close_all(&mh);
Hashmap *homes_by_sysfs;
bool scan_slash_home;
+ UserStorage default_storage;
+ char *default_file_system_type;
sd_event_source *inotify_event_source;
#include <sys/stat.h>
#include <sys/types.h>
+#include "bus-log-control-api.h"
#include "daemon-util.h"
#include "homed-manager.h"
+#include "homed-manager-bus.h"
#include "log.h"
#include "main-func.h"
+#include "service-util.h"
#include "signal-util.h"
static int run(int argc, char *argv[]) {
log_setup_service();
- umask(0022);
+ r = service_parse_argv("systemd-homed.service",
+ "A service to create, remove, change or inspect home areas.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
- if (argc != 1)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+ umask(0022);
if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.Home", 1) < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set $SYSTEMD_BYPASS_USERDB: %m");
--- /dev/null
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See homed.conf(5) for details
+
+[Home]
+#DefaultStorage=
+#DefaultFileSystemType=ext4
#include "fileio.h"
#include "fs-util.h"
#include "fsck-util.h"
+#include "home-util.h"
#include "homework-luks.h"
#include "homework-mount.h"
#include "id128-util.h"
* strictly round disk sizes down to the next 1K boundary.*/
#define DISK_SIZE_ROUND_DOWN(x) ((x) & ~UINT64_C(1023))
-static bool supported_fstype(const char *fstype) {
- /* Limit the set of supported file systems a bit, as protection against little tested kernel file
- * systems. Also, we only support the resize ioctls for these file systems. */
- return STR_IN_SET(fstype, "ext4", "btrfs", "xfs");
-}
-
static int probe_file_system_by_fd(
int fd,
char **ret_fstype,
return 1;
}
-static int run_fitrim(int root_fd) {
+int run_fitrim(int root_fd) {
char buf[FORMAT_BYTES_MAX];
struct fstrim_range range = {
.len = UINT64_MAX,
};
/* If discarding is on, discard everything right after mounting, so that the discard setting takes
- * effect on activation. */
+ * effect on activation. (Also, optionally, trim on logout) */
assert(root_fd >= 0);
if (ioctl(root_fd, FITRIM, &range) < 0) {
- if (IN_SET(errno, ENOTTY, EOPNOTSUPP, EBADF)) {
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EBADF) {
log_debug_errno(errno, "File system does not support FITRIM, not trimming.");
return 0;
}
return 1;
}
-static int run_fallocate(int backing_fd, const struct stat *st) {
+int run_fitrim_by_path(const char *root_path) {
+ _cleanup_close_ int root_fd = -1;
+
+ root_fd = open(root_path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ if (root_fd < 0)
+ return log_error_errno(errno, "Failed to open file system '%s' for trimming: %m", root_path);
+
+ return run_fitrim(root_fd);
+}
+
+int run_fallocate(int backing_fd, const struct stat *st) {
char buf[FORMAT_BYTES_MAX];
+ struct stat stbuf;
assert(backing_fd >= 0);
- assert(st);
/* If discarding is off, let's allocate the whole image before mounting, so that the setting takes
* effect on activation */
+ if (!st) {
+ if (fstat(backing_fd, &stbuf) < 0)
+ return log_error_errno(errno, "Failed to fstat(): %m");
+
+ st = &stbuf;
+ }
+
if (!S_ISREG(st->st_mode))
return 0;
return 1;
}
+int run_fallocate_by_path(const char *backing_path) {
+ _cleanup_close_ int backing_fd = -1;
+
+ backing_fd = open(backing_path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+ if (backing_fd < 0)
+ return log_error_errno(errno, "Failed to open '%s' for fallocate(): %m", backing_path);
+
+ return run_fallocate(backing_fd, NULL);
+}
+
int home_prepare_luks(
UserRecord *h,
bool already_activated,
h->luks_volume_key_size,
h->password,
pkcs11_decrypted_passwords ? *pkcs11_decrypted_passwords : NULL,
- user_record_luks_discard(h),
+ user_record_luks_discard(h) || user_record_luks_offline_discard(h),
&cd,
&found_luks_uuid,
&volume_key,
if (user_record_luks_discard(h))
(void) run_fitrim(root_fd);
+
+ setup->image_fd = TAKE_FD(fd);
+ setup->do_offline_fallocate = !(setup->do_offline_fitrim = user_record_luks_offline_discard(h));
}
setup->loop = TAKE_PTR(loop);
return r;
setup.undo_mount = false;
+ setup.do_offline_fitrim = false;
loop_device_relinquish(setup.loop);
log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
setup.undo_dm = false;
+ setup.do_offline_fallocate = false;
log_info("Everything completed.");
int home_deactivate_luks(UserRecord *h) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
+ bool we_detached;
int r;
/* Note that the DM device and loopback device are set to auto-detach, hence strictly speaking we
r = crypt_init_by_name(&cd, dm_name);
if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
- log_debug_errno(r, "LUKS device %s is already detached.", dm_name);
- return false;
+ log_debug_errno(r, "LUKS device %s has already been detached.", dm_name);
+ we_detached = false;
} else if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
+ else {
+ log_info("Discovered used LUKS device %s.", dm_node);
+
+ crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+
+ r = crypt_deactivate(cd, dm_name);
+ if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
+ log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
+ we_detached = false;
+ } else if (r < 0)
+ return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+ else {
+ log_info("LUKS device detaching completed.");
+ we_detached = true;
+ }
+ }
- log_info("Discovered used LUKS device %s.", dm_node);
+ if (user_record_luks_offline_discard(h))
+ log_debug("Not allocating on logout.");
+ else
+ (void) run_fallocate_by_path(user_record_image_path(h));
- crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+ return we_detached;
+}
- r = crypt_deactivate(cd, dm_name);
- if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT))
- log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
- else if (r < 0)
- return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+int home_trim_luks(UserRecord *h) {
+ assert(h);
+
+ if (!user_record_luks_offline_discard(h)) {
+ log_debug("Not trimming on logout.");
+ return 0;
+ }
- log_info("LUKS device detaching completed.");
- return true;
+ (void) run_fitrim_by_path(user_record_home_directory(h));
+ return 0;
}
static int run_mkfs(
if (asprintf(&disk_uuid_path, "/dev/disk/by-uuid/" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(luks_uuid)) < 0)
return log_oom();
- if (user_record_luks_discard(h)) {
+ if (user_record_luks_discard(h) || user_record_luks_offline_discard(h)) {
+ /* If we want online or offline discard, discard once before we start using things. */
+
if (ioctl(image_fd, BLKDISCARD, (uint64_t[]) { 0, block_device_size }) < 0)
log_full_errno(errno == EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, errno,
"Failed to issue full-device BLKDISCARD on device, ignoring: %m");
user_record_user_name_and_realm(h),
pkcs11_decrypted_passwords,
effective_passwords,
- user_record_luks_discard(h),
+ user_record_luks_discard(h) || user_record_luks_offline_discard(h),
h,
&cd);
if (r < 0)
goto fail;
}
+ if (user_record_luks_offline_discard(h)) {
+ r = run_fitrim(root_fd);
+ if (r < 0)
+ goto fail;
+ }
+
root_fd = safe_close(root_fd);
r = umount_verbose("/run/systemd/user-home-mount");
loop = loop_device_unref(loop);
+ if (!user_record_luks_offline_discard(h)) {
+ r = run_fallocate(image_fd, NULL /* refresh stat() data */);
+ if (r < 0)
+ goto fail;
+ }
+
if (disk_uuid_path)
(void) ioctl(image_fd, BLKRRPART, 0);
int home_activate_luks(UserRecord *h, char ***pkcs11_decrypted_passwords, UserRecord **ret_home);
int home_deactivate_luks(UserRecord *h);
+int home_trim_luks(UserRecord *h);
int home_store_header_identity_luks(UserRecord *h, HomeSetup *setup, UserRecord *old_home);
return (uint64_t) k;
}
+
+int run_fitrim(int root_fd);
+int run_fitrim_by_path(const char *root_path);
+int run_fallocate(int backing_fd, const struct stat *st);
+int run_fallocate_by_path(const char *backing_path);
#include "copy.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "home-util.h"
#include "homework-cifs.h"
#include "homework-directory.h"
assert(setup);
- setup->root_fd = safe_close(setup->root_fd);
+ if (setup->root_fd >= 0) {
+ if (setup->do_offline_fitrim) {
+ q = run_fitrim(setup->root_fd);
+ if (q < 0)
+ r = q;
+ }
+
+ setup->root_fd = safe_close(setup->root_fd);
+ }
if (setup->undo_mount) {
q = umount_verbose("/run/systemd/user-home-mount");
r = q;
}
+ if (setup->image_fd >= 0) {
+ if (setup->do_offline_fallocate) {
+ q = run_fallocate(setup->image_fd, NULL);
+ if (q < 0)
+ r = q;
+ }
+
+ setup->image_fd = safe_close(setup->image_fd);
+ }
+
setup->undo_mount = false;
setup->undo_dm = false;
+ setup->do_offline_fitrim = false;
+ setup->do_offline_fallocate = false;
setup->dm_name = mfree(setup->dm_name);
setup->dm_node = mfree(setup->dm_node);
if (r < 0)
return r;
if (r == USER_TEST_MOUNTED) {
+ if (user_record_storage(h) == USER_LUKS) {
+ r = home_trim_luks(h);
+ if (r < 0)
+ return r;
+ }
+
if (umount2(user_record_home_directory(h), UMOUNT_NOFOLLOW | (force ? MNT_FORCE|MNT_DETACH : 0)) < 0)
return log_error_errno(errno, "Failed to unmount %s: %m", user_record_home_directory(h));
return 0;
}
+static int determine_default_storage(UserStorage *ret) {
+ UserStorage storage = _USER_STORAGE_INVALID;
+ const char *e;
+ int r;
+
+ assert(ret);
+
+ /* homed tells us via an environment variable which default storage to use */
+ e = getenv("SYSTEMD_HOME_DEFAULT_STORAGE");
+ if (e) {
+ storage = user_storage_from_string(e);
+ if (storage < 0)
+ log_warning("$SYSTEMD_HOME_DEFAULT_STORAGE set to invalid storage type, ignoring: %s", e);
+ else {
+ log_info("Using configured default storage '%s'.", user_storage_to_string(storage));
+ *ret = storage;
+ return 0;
+ }
+ }
+
+ /* When neither user nor admin specified the storage type to use, fix it to be LUKS — unless we run
+ * in a container where loopback devices and LUKS/DM are not available. Also, if /home is encrypted
+ * anyway, let's avoid duplicate encryption. Note that we typically default to the assumption of
+ * "classic" storage for most operations. However, if we create a new home, then let's user LUKS if
+ * nothing is specified. */
+
+ r = detect_container();
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether we are in a container: %m");
+ if (r == 0) {
+ r = path_is_encrypted("/home");
+ if (r < 0)
+ log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
+ if (r <= 0) {
+ log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
+ *ret = USER_LUKS;
+ return 0;
+ }
+
+ log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
+ } else
+ log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS));
+
+ r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC);
+ if (r < 0)
+ log_warning_errno(r, "Failed to determine file system of /home, ignoring: %m");
+ if (r > 0) {
+ log_info("/home is on btrfs, using '%s' as storage.", user_storage_to_string(USER_SUBVOLUME));
+ *ret = USER_SUBVOLUME;
+ } else {
+ log_info("/home is on simple file system, using '%s' as storage.", user_storage_to_string(USER_DIRECTORY));
+ *ret = USER_DIRECTORY;
+ }
+
+ return 0;
+}
+
static int home_create(UserRecord *h, UserRecord **ret_home) {
_cleanup_(strv_free_erasep) char **effective_passwords = NULL, **pkcs11_decrypted_passwords = NULL;
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
+ UserStorage new_storage = _USER_STORAGE_INVALID;
+ const char *new_fs = NULL;
int r;
assert(h);
if (r != USER_TEST_ABSENT)
return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Home directory %s already exists, refusing.", user_record_home_directory(h));
- /* When the user didn't specify the storage type to use, fix it to be LUKS -- unless we run in a
- * container where loopback devices and LUKS/DM are not available. Note that we typically default to
- * the assumption of "classic" storage for most operations. However, if we create a new home, then
- * let's user LUKS if nothing is specified. */
if (h->storage < 0) {
- UserStorage new_storage;
-
- r = detect_container();
+ r = determine_default_storage(&new_storage);
if (r < 0)
- return log_error_errno(r, "Failed to determine whether we are in a container: %m");
- if (r > 0) {
- new_storage = USER_DIRECTORY;
-
- r = path_is_fs_type("/home", BTRFS_SUPER_MAGIC);
- if (r < 0)
- log_debug_errno(r, "Failed to determine file system of /home, ignoring: %m");
+ return r;
+ }
- new_storage = r > 0 ? USER_SUBVOLUME : USER_DIRECTORY;
- } else
- new_storage = USER_LUKS;
+ if ((h->storage == USER_LUKS ||
+ (h->storage < 0 && new_storage == USER_LUKS)) &&
+ !h->file_system_type)
+ new_fs = getenv("SYSTEMD_HOME_DEFAULT_FILE_SYSTEM_TYPE");
+ if (new_storage >= 0 || new_fs) {
r = user_record_add_binding(
h,
new_storage,
NULL,
NULL,
UINT64_MAX,
- NULL,
+ new_fs,
NULL,
UID_INVALID,
GID_INVALID);
if (r < 0)
return log_error_errno(r, "Failed to change storage type to LUKS: %m");
-
- if (!h->image_path_auto) {
- h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), new_storage == USER_LUKS ? ".home" : ".homedir");
- if (!h->image_path_auto)
- return log_oom();
- }
}
r = user_record_test_image_path_and_warn(h);
assert(ip);
if (stat(ip, &st) < 0) {
- if (errno != -ENOENT)
+ if (errno != ENOENT)
return log_error_errno(errno, "Failed to stat() %s: %m", ip);
} else {
LoopDevice *loop;
struct crypt_device *crypt_device;
int root_fd;
+ int image_fd;
sd_id128_t found_partition_uuid;
sd_id128_t found_luks_uuid;
sd_id128_t found_fs_uuid;
bool undo_dm;
bool undo_mount;
+ bool do_offline_fitrim;
+ bool do_offline_fallocate;
uint64_t partition_offset;
uint64_t partition_size;
#define HOME_SETUP_INIT \
{ \
.root_fd = -1, \
+ .image_fd = -1, \
.partition_offset = UINT64_MAX, \
.partition_size = UINT64_MAX, \
}
home-util.h
homed-bus.c
homed-bus.h
+ homed-conf.c
+ homed-conf.h
homed-home-bus.c
homed-home-bus.h
homed-home.c
user-record-util.h
'''.split())
+homed_gperf_c = custom_target(
+ 'homed_gperf.c',
+ input : 'homed-gperf.gperf',
+ output : 'homed-gperf.c',
+ command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
+
+systemd_homed_sources += [homed_gperf_c]
+
homectl_sources = files('''
home-util.c
home-util.h
install_dir : dbussystemservicedir)
install_data('org.freedesktop.home1.policy',
install_dir : polkitpolicydir)
+
+ install_data('homed.conf',
+ install_dir : pkgsysconfdir)
endif
#include "user-record.h"
#include "user-util.h"
-/* Used for the "systemd-user-record-is-homed" PAM data field, to indicate whether we know whether this user
- * record is managed by homed or by something else. */
-#define USER_RECORD_IS_HOMED INT_TO_PTR(1)
-#define USER_RECORD_IS_OTHER INT_TO_PTR(2)
-
-static const BusLocator home_mgr = {
- .destination = "org.freedesktop.home1",
- .path = "/org/freedesktop/home1",
- .interface = "org.freedesktop.home1.Manager",
-};
-
static int parse_argv(
pam_handle_t *handle,
int argc, const char **argv,
return 0;
}
+static int parse_env(
+ pam_handle_t *handle,
+ bool *please_suspend) {
+
+ const char *v;
+ int r;
+
+ /* Let's read the suspend setting from an env var in addition to the PAM command line. That makes it
+ * easy to declare the features of a display manager in code rather than configuration, and this is
+ * really a feature of code */
+
+ v = pam_getenv(handle, "SYSTEMD_HOME_SUSPEND");
+ if (!v) {
+ /* Also check the process env block, so that people can control this via an env var from the
+ * outside of our process. */
+ v = secure_getenv("SYSTEMD_HOME_SUSPEND");
+ if (!v)
+ return 0;
+ }
+
+ r = parse_boolean(v);
+ if (r < 0)
+ pam_syslog(handle, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v);
+ else if (please_suspend)
+ *please_suspend = r;
+
+ return 0;
+}
+
static int acquire_user_record(
pam_handle_t *handle,
+ const char *username,
UserRecord **ret_record) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
- const char *username = NULL, *json = NULL;
- const void *b = NULL;
+ _cleanup_free_ char *homed_field = NULL;
+ const char *json = NULL;
int r;
assert(handle);
- r = pam_get_user(handle, &username, NULL);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
- return r;
- }
+ if (!username) {
+ r = pam_get_user(handle, &username, NULL);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
+ return r;
+ }
- if (isempty(username)) {
- pam_syslog(handle, LOG_ERR, "User name not set.");
- return PAM_SERVICE_ERR;
+ if (isempty(username)) {
+ pam_syslog(handle, LOG_ERR, "User name not set.");
+ return PAM_SERVICE_ERR;
+ }
}
/* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for
if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username, 0))
return PAM_USER_UNKNOWN;
- /* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */
- r = pam_get_data(handle, "systemd-user-record-is-homed", &b);
+ /* We cache the user record in the PAM context. We use a field name that includes the username, since
+ * clients might change the user name associated with a PAM context underneath us. Notably, 'sudo'
+ * creates a single PAM context and first authenticates it with the user set to the originating user,
+ * then updates the user for the destination user and issues the session stack with the same PAM
+ * context. We thus must be prepared that the user record changes between calls and we keep any
+ * caching separate. */
+ homed_field = strjoin("systemd-home-user-record-", username);
+ if (!homed_field)
+ return pam_log_oom(handle);
+
+ /* Let's use the cache, so that we can share it between the session and the authentication hooks */
+ r = pam_get_data(handle, homed_field, (const void**) &json);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
- /* Failure */
- pam_syslog(handle, LOG_ERR, "Failed to get PAM user-record-is-homed flag: %s", pam_strerror(handle, r));
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
return r;
- } else if (b == NULL)
- /* Nothing cached yet, need to acquire fresh */
- json = NULL;
- else if (b != USER_RECORD_IS_HOMED)
- /* Definitely not a homed record */
- return PAM_USER_UNKNOWN;
- else {
- /* It's a homed record, let's use the cache, so that we can share it between the session and
- * the authentication hooks */
- r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
- if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
- pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
- return r;
- }
}
-
- if (!json) {
+ if (r == PAM_SUCCESS && json) {
+ /* We determined earlier that this is not a homed user? Then exit early. (We use -1 as
+ * negative cache indicator) */
+ if (json == (void*) -1)
+ return PAM_USER_UNKNOWN;
+ } else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *json_copy = NULL;
+ _cleanup_free_ char *generic_field = NULL, *json_copy = NULL;
r = pam_acquire_bus_connection(handle, &bus);
if (r != PAM_SUCCESS)
return r;
- r = bus_call_method(bus, &home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
+ r = bus_call_method(bus, bus_home_mgr, "GetUserRecordByName", &error, &reply, "s", username);
if (r < 0) {
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN) ||
sd_bus_error_has_name(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER)) {
if (r < 0)
return pam_bus_log_parse_error(handle, r);
+ /* First copy: for the homed-specific data field, i.e. where we know the user record is from
+ * homed */
json_copy = strdup(json);
if (!json_copy)
return pam_log_oom(handle);
- r = pam_set_data(handle, "systemd-user-record", json_copy, pam_cleanup_free);
+ r = pam_set_data(handle, homed_field, json_copy, pam_cleanup_free);
if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r));
+ pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
+ homed_field, pam_strerror(handle, r));
return r;
}
- TAKE_PTR(json_copy);
+ /* Take a second copy: for the generic data field, the one which we share with
+ * pam_systemd. While we insist on only reusing homed records, pam_systemd is fine with homed
+ * and non-homed user records. */
+ json_copy = strdup(json);
+ if (!json_copy)
+ return pam_log_oom(handle);
+
+ generic_field = strjoin("systemd-user-record-", username);
+ if (!generic_field)
+ return pam_log_oom(handle);
- r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_HOMED, NULL);
+ r = pam_set_data(handle, generic_field, json_copy, pam_cleanup_free);
if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set PAM user record is homed flag: %s", pam_strerror(handle, r));
+ pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
+ homed_field, pam_strerror(handle, r));
return r;
}
+
+ TAKE_PTR(json_copy);
}
r = json_parse(json, JSON_PARSE_SENSITIVE, &v, NULL, NULL);
return PAM_SERVICE_ERR;
}
+ /* Safety check if cached record actually matches what we are looking for */
if (!streq_ptr(username, ur->user_name)) {
pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
return PAM_SERVICE_ERR;
user_unknown:
/* Cache this, so that we don't check again */
- r = pam_set_data(handle, "systemd-user-record-is-homed", USER_RECORD_IS_OTHER, NULL);
+ r = pam_set_data(handle, homed_field, (void*) -1, NULL);
if (r != PAM_SUCCESS)
- pam_syslog(handle, LOG_ERR, "Failed to set PAM user-record-is-homed flag, ignoring: %s", pam_strerror(handle, r));
+ pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s' to invalid, ignoring: %s",
+ homed_field, pam_strerror(handle, r));
return PAM_USER_UNKNOWN;
}
-static int release_user_record(pam_handle_t *handle) {
+static int release_user_record(pam_handle_t *handle, const char *username) {
+ _cleanup_free_ char *homed_field = NULL, *generic_field = NULL;
int r, k;
- r = pam_set_data(handle, "systemd-user-record", NULL, NULL);
+ assert(handle);
+ assert(username);
+
+ homed_field = strjoin("systemd-home-user-record-", username);
+ if (!homed_field)
+ return pam_log_oom(handle);
+
+ r = pam_set_data(handle, homed_field, NULL, NULL);
if (r != PAM_SUCCESS)
- pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data: %s", pam_strerror(handle, r));
+ pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", homed_field, pam_strerror(handle, r));
- k = pam_set_data(handle, "systemd-user-record-is-homed", NULL, NULL);
+ generic_field = strjoin("systemd-user-record-", username);
+ if (!generic_field)
+ return pam_log_oom(handle);
+
+ k = pam_set_data(handle, generic_field, NULL, NULL);
if (k != PAM_SUCCESS)
- pam_syslog(handle, LOG_ERR, "Failed to release PAM user-record-is-homed flag: %s", pam_strerror(handle, k));
+ pam_syslog(handle, LOG_ERR, "Failed to release PAM user record data '%s': %s", generic_field, pam_strerror(handle, k));
return IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA) ? k : r;
}
if (strv_isempty(secret->password))
r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Password: ");
- else
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Password incorrect or not sufficient for authentication of user %s, please try again: ", user_name);
+ else {
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password incorrect or not sufficient for authentication of user %s.", user_name);
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, try again: ");
+ }
if (r != PAM_SUCCESS)
return PAM_CONV_ERR; /* no logging here */
} else if (sd_bus_error_has_name(error, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN)) {
_cleanup_(erase_and_freep) char *newp = NULL;
- if (strv_isempty(secret->password))
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token of user %s not inserted, please enter password: ", user_name);
- else
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Password incorrect or not sufficient, and configured security token of user %s not inserted, please enter password: ", user_name);
+ if (strv_isempty(secret->password)) {
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token of user %s not inserted.", user_name);
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Try again with password: ");
+ } else {
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password incorrect or not sufficient, and configured security token of user %s not inserted.", user_name);
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Try again with password: ");
+ }
if (r != PAM_SUCCESS)
return PAM_CONV_ERR; /* no logging here */
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_NEEDED)) {
_cleanup_(erase_and_freep) char *newp = NULL;
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Please enter security token PIN: ");
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN: ");
if (r != PAM_SUCCESS)
return PAM_CONV_ERR; /* no logging here */
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN)) {
_cleanup_(erase_and_freep) char *newp = NULL;
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN incorrect, please enter PIN for security token of user %s again: ", user_name);
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN incorrect for user %s.", user_name);
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: ");
if (r != PAM_SUCCESS)
return PAM_CONV_ERR; /* no logging here */
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT)) {
_cleanup_(erase_and_freep) char *newp = NULL;
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN incorrect (only a few tries left!), please enter PIN for security token of user %s again: ", user_name);
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN of user %s incorrect (only a few tries left!)", user_name);
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: ");
if (r != PAM_SUCCESS)
return PAM_CONV_ERR; /* no logging here */
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT)) {
_cleanup_(erase_and_freep) char *newp = NULL;
- r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Security token PIN incorrect (only one try left!), please enter PIN for security token of user %s again: ", user_name);
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN of user %s incorrect (only one try left!)", user_name);
+ r = pam_prompt(handle, PAM_PROMPT_ECHO_OFF, &newp, "Sorry, retry security token PIN: ");
if (r != PAM_SUCCESS)
return PAM_CONV_ERR; /* no logging here */
bool do_auth = please_authenticate, home_not_active = false, home_locked = false;
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
_cleanup_close_ int acquired_fd = -1;
+ _cleanup_free_ char *fd_field = NULL;
const void *home_fd_ptr = NULL;
+ const char *username = NULL;
unsigned n_attempts = 0;
int r;
* authenticates, while the other PAM hooks unset it so that they can a ref of their own without
* authentication if possible, but with authentication if necessary. */
+ r = pam_get_user(handle, &username, NULL);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
+ return r;
+ }
+
+ if (isempty(username)) {
+ pam_syslog(handle, LOG_ERR, "User name not set.");
+ return PAM_SERVICE_ERR;
+ }
+
/* If we already have acquired the fd, let's shortcut this */
- r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
- if (r == PAM_SUCCESS && PTR_TO_INT(home_fd_ptr) >= 0)
+ fd_field = strjoin("systemd-home-fd-", username);
+ if (!fd_field)
+ return pam_log_oom(handle);
+
+ r = pam_get_data(handle, fd_field, &home_fd_ptr);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to retrieve PAM home reference fd: %s", pam_strerror(handle, r));
+ return r;
+ }
+ if (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) >= 0)
return PAM_SUCCESS;
r = pam_acquire_bus_connection(handle, &bus);
if (r != PAM_SUCCESS)
return r;
- r = acquire_user_record(handle, &ur);
+ r = acquire_user_record(handle, username, &ur);
if (r != PAM_SUCCESS)
return r;
}
}
- r = bus_message_new_method_call(bus, &m, &home_mgr, do_auth ? "AcquireHome" : "RefHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, do_auth ? "AcquireHome" : "RefHome");
if (r < 0)
return pam_bus_log_create_error(handle, r);
do_auth = true;
}
- r = pam_set_data(handle, "systemd-home-fd", FD_TO_PTR(acquired_fd), cleanup_home_fd);
+ r = pam_set_data(handle, fd_field, FD_TO_PTR(acquired_fd), cleanup_home_fd);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM bus data: %s", pam_strerror(handle, r));
return r;
/* We likely just activated the home directory, let's flush out the user record, since a
* newer embedded user record might have been acquired from the activation. */
- r = release_user_record(handle);
+ r = release_user_record(handle, ur->user_name);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return r;
}
return PAM_SUCCESS;
}
-static int release_home_fd(pam_handle_t *handle) {
+static int release_home_fd(pam_handle_t *handle, const char *username) {
+ _cleanup_free_ char *fd_field = NULL;
const void *home_fd_ptr = NULL;
int r;
- r = pam_get_data(handle, "systemd-home-fd", &home_fd_ptr);
- if (r == PAM_NO_MODULE_DATA || PTR_TO_FD(home_fd_ptr) < 0)
+ assert(handle);
+ assert(username);
+
+ fd_field = strjoin("systemd-home-fd-", username);
+ if (!fd_field)
+ return pam_log_oom(handle);
+
+ r = pam_get_data(handle, fd_field, &home_fd_ptr);
+ if (r == PAM_NO_MODULE_DATA || (r == PAM_SUCCESS && PTR_TO_FD(home_fd_ptr) < 0))
return PAM_NO_MODULE_DATA;
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to retrieve PAM home reference fd: %s", pam_strerror(handle, r));
+ return r;
+ }
- r = pam_set_data(handle, "systemd-home-fd", NULL, NULL);
+ r = pam_set_data(handle, fd_field, NULL, NULL);
if (r != PAM_SUCCESS)
pam_syslog(handle, LOG_ERR, "Failed to release PAM home reference fd: %s", pam_strerror(handle, r));
bool debug = false, suspend_please = false;
+ if (parse_env(handle, &suspend_please) < 0)
+ return PAM_AUTH_ERR;
+
if (parse_argv(handle,
argc, argv,
&suspend_please,
bool debug = false, suspend_please = false;
int r;
+ if (parse_env(handle, &suspend_please) < 0)
+ return PAM_SESSION_ERR;
+
if (parse_argv(handle,
argc, argv,
&suspend_please,
return r;
}
+ r = pam_putenv(handle, suspend_please ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0");
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: %s", pam_strerror(handle, r));
+ return r;
+ }
+
/* Let's release the D-Bus connection, after all the session might live quite a long time, and we are
* not going to process the bus connection in that time, so let's better close before the daemon
* kicks us off because we are not processing anything. */
if (debug)
pam_syslog(handle, LOG_DEBUG, "pam-systemd-homed session end");
+ r = pam_get_user(handle, &username, NULL);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
+ return r;
+ }
+
+ if (isempty(username)) {
+ pam_syslog(handle, LOG_ERR, "User name not set.");
+ return PAM_SERVICE_ERR;
+ }
+
/* Let's explicitly drop the reference to the homed session, so that the subsequent ReleaseHome()
* call will be able to do its thing. */
- r = release_home_fd(handle);
+ r = release_home_fd(handle, username);
if (r == PAM_NO_MODULE_DATA) /* Nothing to do, we never acquired an fd */
return PAM_SUCCESS;
if (r != PAM_SUCCESS)
return r;
- r = pam_get_user(handle, &username, NULL);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to get user name: %s", pam_strerror(handle, r));
- return r;
- }
-
r = pam_acquire_bus_connection(handle, &bus);
if (r != PAM_SUCCESS)
return r;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ReleaseHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ReleaseHome");
if (r < 0)
return pam_bus_log_create_error(handle, r);
usec_t t;
int r;
+ if (parse_env(handle, &please_suspend) < 0)
+ return PAM_AUTH_ERR;
+
if (parse_argv(handle,
argc, argv,
&please_suspend,
if (r != PAM_SUCCESS)
return r;
- r = acquire_user_record(handle, &ur);
+ r = acquire_user_record(handle, NULL, &ur);
if (r != PAM_SUCCESS)
return r;
if (r != PAM_SUCCESS)
return r;
- r = acquire_user_record(handle, &ur);
+ r = acquire_user_record(handle, NULL, &ur);
if (r != PAM_SUCCESS)
return r;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = bus_message_new_method_call(bus, &m, &home_mgr, "ChangePasswordHome");
+ r = bus_message_new_method_call(bus, &m, bus_home_mgr, "ChangePasswordHome");
if (r < 0)
return pam_bus_log_create_error(handle, r);
pwquality_maybe_disable_dictionary(pwq);
- suggestions = new0(char*, N_SUGGESTIONS);
+ suggestions = new0(char*, N_SUGGESTIONS+1);
if (!suggestions)
return log_oom();
_cleanup_(json_variant_unrefp) JsonVariant *new_binding_entry = NULL, *binding = NULL;
char smid[SD_ID128_STRING_MAX], partition_uuids[37], luks_uuids[37], fs_uuids[37];
- _cleanup_free_ char *ip = NULL, *hd = NULL;
+ _cleanup_free_ char *ip = NULL, *hd = NULL, *ip_auto = NULL, *lc = NULL, *lcm = NULL, *fst = NULL;
sd_id128_t mid;
int r;
ip = strdup(image_path);
if (!ip)
return -ENOMEM;
+ } else if (!h->image_path && storage >= 0) {
+ r = user_record_build_image_path(storage, user_record_user_name_and_realm(h), &ip_auto);
+ if (r < 0)
+ return r;
}
if (home_directory) {
return -ENOMEM;
}
+ if (file_system_type) {
+ fst = strdup(file_system_type);
+ if (!fst)
+ return -ENOMEM;
+ }
+
+ if (luks_cipher) {
+ lc = strdup(luks_cipher);
+ if (!lc)
+ return -ENOMEM;
+ }
+
+ if (luks_cipher_mode) {
+ lcm = strdup(luks_cipher_mode);
+ if (!lcm)
+ return -ENOMEM;
+ }
+
r = json_build(&new_binding_entry,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR_CONDITION(!!image_path, "imagePath", JSON_BUILD_STRING(image_path)),
if (ip)
free_and_replace(h->image_path, ip);
+ if (ip_auto)
+ free_and_replace(h->image_path_auto, ip_auto);
if (!sd_id128_is_null(partition_uuid))
h->partition_uuid = partition_uuid;
if (!sd_id128_is_null(fs_uuid))
h->file_system_uuid = fs_uuid;
+ if (lc)
+ free_and_replace(h->luks_cipher, lc);
+ if (lcm)
+ free_and_replace(h->luks_cipher_mode, lcm);
+ if (luks_volume_key_size != UINT64_MAX)
+ h->luks_volume_key_size = luks_volume_key_size;
+
+ if (fst)
+ free_and_replace(h->file_system_type, fst);
if (hd)
free_and_replace(h->home_directory, hd);
if (uid_is_valid(uid))
h->uid = uid;
+ if (gid_is_valid(gid))
+ h->gid = gid;
h->mask |= USER_RECORD_BINDING;
return 1;
if (r < 0)
return r;
+ json_variant_sensitive(w);
+
r = json_variant_set_field(&h->json, "secret", w);
if (r < 0)
return r;
if (r < 0)
return r;
+ json_variant_sensitive(w);
+
r = json_variant_set_field(&h->json, "secret", w);
if (r < 0)
return r;
if (json_variant_is_blank_object(w))
r = json_variant_filter(&h->json, STRV_MAKE("secret"));
- else
+ else {
+ json_variant_sensitive(w);
+
r = json_variant_set_field(&h->json, "secret", w);
+ }
if (r < 0)
return r;
#include "parse-util.h"
#include "path-util.h"
#include "selinux-util.h"
+#include "service-util.h"
#include "signal-util.h"
#include "strv.h"
#include "user-util.h"
PROP_CHASSIS,
PROP_DEPLOYMENT,
PROP_LOCATION,
- PROP_KERNEL_NAME,
- PROP_KERNEL_RELEASE,
- PROP_KERNEL_VERSION,
PROP_OS_PRETTY_NAME,
PROP_OS_CPE_NAME,
PROP_HOME_URL,
typedef struct Context {
char *data[_PROP_MAX];
Hashmap *polkit_registry;
- sd_id128_t uuid;
- bool has_uuid;
} Context;
static void context_reset(Context *c) {
c->data[p] = mfree(c->data[p]);
}
-static void context_clear(Context *c) {
+static void context_destroy(Context *c) {
assert(c);
context_reset(c);
static int context_read_data(Context *c) {
int r;
- struct utsname u;
assert(c);
context_reset(c);
- assert_se(uname(&u) >= 0);
- c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
- c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
- c->data[PROP_KERNEL_VERSION] = strdup(u.version);
- if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
- !c->data[PROP_KERNEL_VERSION])
- return -ENOMEM;
-
c->data[PROP_HOSTNAME] = gethostname_malloc();
if (!c->data[PROP_HOSTNAME])
return -ENOMEM;
if (r < 0 && r != -ENOENT)
return r;
- r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid);
- if (r == -ENOENT)
- r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &c->uuid);
- if (r < 0)
- log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to read product UUID, ignoring: %m");
- else if (sd_id128_is_null(c->uuid) || sd_id128_is_allf(c->uuid))
- log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(c->uuid));
- else
- c->has_uuid = true;
-
return 0;
}
if (hostname_is_useful(static_hn))
hn = static_hn;
- /* ... the transient host name, (ie: DHCP) comes next ... */
+ /* ... the transient hostname, (ie: DHCP) comes next ... */
else if (!isempty(c->data[PROP_HOSTNAME]))
hn = c->data[PROP_HOSTNAME];
return sd_bus_message_append(reply, "s", name);
}
+static int property_get_uname_field(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ struct utsname u;
+
+ assert_se(uname(&u) >= 0);
+
+ return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
+}
+
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *name;
r = context_update_kernel_hostname(c);
if (r < 0) {
- log_error_errno(r, "Failed to set host name: %m");
+ log_error_errno(r, "Failed to set hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
}
- log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
+ log_info("Changed hostname to '%s'", strna(c->data[PROP_HOSTNAME]));
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
r = context_update_kernel_hostname(c);
if (r < 0) {
- log_error_errno(r, "Failed to set host name: %m");
+ log_error_errno(r, "Failed to set hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
}
r = context_write_data_static_hostname(c);
if (r < 0) {
- log_error_errno(r, "Failed to write static host name: %m");
+ log_error_errno(r, "Failed to write static hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
}
- log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
+ log_info("Changed static hostname to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
if (prop == PROP_ICON_NAME && !filename_is_valid(name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
if (prop == PROP_CHASSIS && !valid_chassis(name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
}
log_info("Changed %s to '%s'",
- prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
+ prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
prop == PROP_DEPLOYMENT ? "deployment" :
prop == PROP_LOCATION ? "location" :
prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Context *c = userdata;
+ bool has_uuid = false;
int interactive, r;
+ sd_id128_t uuid;
assert(m);
assert(c);
- if (!c->has_uuid)
- return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid");
+ r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
+ if (r == -ENOENT)
+ r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
+ if (r < 0)
+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to read product UUID, ignoring: %m");
+ else if (sd_id128_is_null(uuid) || sd_id128_is_allf(uuid))
+ log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(uuid));
+ else
+ has_uuid = true;
+
+ if (!has_uuid)
+ return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
+ "Failed to read product UUID from firmware.");
r = sd_bus_message_read(m, "b", &interactive);
if (r < 0)
if (r < 0)
return r;
- r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid));
+ r = sd_bus_message_append_array(reply, 'y', &uuid, sizeof(uuid));
if (r < 0)
return r;
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END,
};
+static const BusObjectImplementation manager_object = {
+ "/org/freedesktop/hostname1",
+ "org.freedesktop.hostname1",
+ .vtables = BUS_VTABLES(hostname_vtable),
+};
+
static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
if (r < 0)
return log_error_errno(r, "Failed to get system bus connection: %m");
- r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
+ r = bus_add_implementation(bus, &manager_object, c);
if (r < 0)
- return log_error_errno(r, "Failed to register object: %m");
+ return r;
r = bus_log_control_api_register(bus);
if (r < 0)
}
static int run(int argc, char *argv[]) {
- _cleanup_(context_clear) Context context = {};
+ _cleanup_(context_destroy) Context context = {};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
log_setup_service();
+ r = service_parse_argv("systemd-hostnamed.service",
+ "Manage the system hostname and related metadata.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
+
umask(0022);
mac_selinux_init();
- if (argc != 1) {
- log_error("This program takes no arguments.");
- return -EINVAL;
- }
-
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = sd_event_default(&event);
<vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
<action id="org.freedesktop.hostname1.set-hostname">
- <description gettext-domain="systemd">Set host name</description>
- <message gettext-domain="systemd">Authentication is required to set the local host name.</message>
+ <description gettext-domain="systemd">Set hostname</description>
+ <message gettext-domain="systemd">Authentication is required to set the local hostname.</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
</action>
<action id="org.freedesktop.hostname1.set-static-hostname">
- <description gettext-domain="systemd">Set static host name</description>
- <message gettext-domain="systemd">Authentication is required to set the statically configured local host name, as well as the pretty host name.</message>
+ <description gettext-domain="systemd">Set static hostname</description>
+ <message gettext-domain="systemd">Authentication is required to set the statically configured local hostname, as well as the pretty hostname.</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
progress.limit = (RateLimit) { 200*USEC_PER_MSEC, 1 };
/* Hook into SIGINT/SIGTERM, so that we can cancel things then */
- assert(sigaction(SIGINT, &sa, &old_sigint_sa) >= 0);
- assert(sigaction(SIGTERM, &sa, &old_sigterm_sa) >= 0);
+ assert_se(sigaction(SIGINT, &sa, &old_sigint_sa) >= 0);
+ assert_se(sigaction(SIGTERM, &sa, &old_sigterm_sa) >= 0);
r = btrfs_subvol_snapshot_fd_full(
fd,
finish:
/* Put old signal handlers into place */
- assert(sigaction(SIGINT, &old_sigint_sa, NULL) >= 0);
- assert(sigaction(SIGTERM, &old_sigterm_sa, NULL) >= 0);
+ assert_se(sigaction(SIGINT, &old_sigint_sa, NULL) >= 0);
+ assert_se(sigaction(SIGTERM, &old_sigterm_sa, NULL) >= 0);
return 0;
}
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-log-control-api.h"
+#include "bus-util.h"
#include "bus-polkit.h"
#include "def.h"
#include "fd-util.h"
#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "service-util.h"
#include "socket-util.h"
#include "stat-util.h"
#include "string-table.h"
t->stdin_fd = safe_close(t->stdin_fd);
- r = sd_event_add_child(t->manager->event, &t->pid_event_source, t->pid, WEXITED, transfer_on_pid, t);
+ r = sd_event_add_child(t->manager->event, &t->pid_event_source,
+ t->pid, WEXITED, transfer_on_pid, t);
if (r < 0)
return r;
- r = sd_event_add_io(t->manager->event, &t->log_event_source, t->log_fd, EPOLLIN, transfer_on_log, t);
+ r = sd_event_add_io(t->manager->event, &t->log_event_source,
+ t->log_fd, EPOLLIN, transfer_on_log, t);
if (r < 0)
return r;
.iov_base = buf,
.iov_len = sizeof(buf)-1,
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
- struct ucred *ucred = NULL;
+ struct ucred *ucred;
Manager *m = userdata;
- struct cmsghdr *cmsg;
char *p, *e;
Transfer *t;
Iterator i;
ssize_t n;
int r;
- n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0;
-
- return -errno;
- }
+ n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (IN_SET(n, -EAGAIN, -EINTR))
+ return 0;
+ if (n < 0)
+ return (int) n;
cmsg_close_all(&msghdr);
- CMSG_FOREACH(cmsg, &msghdr)
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
- ucred = (struct ucred*) CMSG_DATA(cmsg);
-
if (msghdr.msg_flags & MSG_TRUNC) {
log_warning("Got overly long notification datagram, ignoring.");
return 0;
}
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid <= 0) {
log_warning("Got notification datagram lacking credential information, ignoring.");
return 0;
if (r < 0)
return r;
- r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_on_notify, m);
+ r = sd_event_add_io(m->event, &m->notify_event_source,
+ m->notify_fd, EPOLLIN, manager_on_notify, m);
if (r < 0)
return r;
return -EINVAL;
if (!machine_name_is_valid(local))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Local name %s is invalid", local);
r = setup_machine_directory(error);
if (r < 0)
return r;
- type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ? TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
+ type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ?
+ TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
r = transfer_new(m, &t);
if (r < 0)
return r;
if (!machine_name_is_valid(local))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Local name %s is invalid", local);
r = setup_machine_directory(error);
if (r < 0)
return r;
if (!machine_name_is_valid(local))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Local name %s is invalid", local);
if (fstat(fd, &st) < 0)
return -errno;
if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
return -EINVAL;
- type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
+ type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ?
+ TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
r = transfer_new(m, &t);
if (r < 0)
return r;
if (!http_url_is_valid(remote))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "URL %s is invalid", remote);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "URL %s is invalid", remote);
if (isempty(local))
local = NULL;
else if (!machine_name_is_valid(local))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Local name %s is invalid", local);
if (isempty(verify))
v = IMPORT_VERIFY_SIGNATURE;
else
v = import_verify_from_string(verify);
if (v < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Unknown verification mode %s", verify);
r = setup_machine_directory(error);
if (r < 0)
return r;
- type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
+ type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ?
+ TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
if (manager_find(m, type, remote))
- return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
+ return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS,
+ "Transfer for %s already in progress.", remote);
r = transfer_new(m, &t);
if (r < 0)
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, transfer_type, TransferType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_verify, import_verify, ImportVerify);
+static int transfer_object_find(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ void *userdata,
+ void **found,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ Transfer *t;
+ const char *p;
+ uint32_t id;
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(interface);
+ assert(found);
+ assert(m);
+
+ p = startswith(path, "/org/freedesktop/import1/transfer/_");
+ if (!p)
+ return 0;
+
+ r = safe_atou32(p, &id);
+ if (r < 0 || id == 0)
+ return 0;
+
+ t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
+ if (!t)
+ return 0;
+
+ *found = t;
+ return 1;
+}
+
+static int transfer_node_enumerator(
+ sd_bus *bus,
+ const char *path,
+ void *userdata,
+ char ***nodes,
+ sd_bus_error *error) {
+
+ _cleanup_strv_free_ char **l = NULL;
+ Manager *m = userdata;
+ Transfer *t;
+ unsigned k = 0;
+ Iterator i;
+
+ l = new0(char*, hashmap_size(m->transfers) + 1);
+ if (!l)
+ return -ENOMEM;
+
+ HASHMAP_FOREACH(t, m->transfers, i) {
+
+ l[k] = strdup(t->object_path);
+ if (!l[k])
+ return -ENOMEM;
+
+ k++;
+ }
+
+ *nodes = TAKE_PTR(l);
+
+ return 1;
+}
+
static const sd_bus_vtable transfer_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_VTABLE_END,
};
+static const BusObjectImplementation transfer_object = {
+ "/org/freedesktop/import1/transfer",
+ "org.freedesktop.import1.Transfer",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({transfer_vtable, transfer_object_find}),
+ .node_enumerator = transfer_node_enumerator,
+};
+
static const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_VTABLE_END,
};
-static int transfer_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- Transfer *t;
- const char *p;
- uint32_t id;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- p = startswith(path, "/org/freedesktop/import1/transfer/_");
- if (!p)
- return 0;
-
- r = safe_atou32(p, &id);
- if (r < 0 || id == 0)
- return 0;
-
- t = hashmap_get(m->transfers, UINT32_TO_PTR(id));
- if (!t)
- return 0;
-
- *found = t;
- return 1;
-}
-
-static int transfer_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
- _cleanup_strv_free_ char **l = NULL;
- Manager *m = userdata;
- Transfer *t;
- unsigned k = 0;
- Iterator i;
-
- l = new0(char*, hashmap_size(m->transfers) + 1);
- if (!l)
- return -ENOMEM;
-
- HASHMAP_FOREACH(t, m->transfers, i) {
-
- l[k] = strdup(t->object_path);
- if (!l[k])
- return -ENOMEM;
-
- k++;
- }
-
- *nodes = TAKE_PTR(l);
-
- return 1;
-}
+static const BusObjectImplementation manager_object = {
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ .vtables = BUS_VTABLES(manager_vtable),
+ .children = BUS_IMPLEMENTATIONS(&transfer_object),
+};
static int manager_add_bus_objects(Manager *m) {
int r;
assert(m);
- r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/import1", "org.freedesktop.import1.Manager", manager_vtable, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register object: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/import1/transfer", "org.freedesktop.import1.Transfer", transfer_vtable, transfer_object_find, m);
+ r = bus_add_implementation(m->bus, &manager_object, m);
if (r < 0)
- return log_error_errno(r, "Failed to register object: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/import1/transfer", transfer_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add transfer enumerator: %m");
+ return r;
r = bus_log_control_api_register(m->bus);
if (r < 0)
log_setup_service();
- umask(0022);
+ r = service_parse_argv("systemd-importd.service",
+ "VM and container image import and export service.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
- if (argc != 1) {
- log_error("This program takes no arguments.");
- return -EINVAL;
- }
+ umask(0022);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
assert(s);
assert(n_sockets > 0);
- zero(*s);
+ *s = (struct Server) {
+ .epoll_fd = epoll_create1(EPOLL_CLOEXEC),
+ };
- s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (s->epoll_fd < 0) {
r = log_error_errno(errno,
"Failed to create epoll object: %m");
}
for (i = 0; i < n_sockets; i++) {
- struct epoll_event ev;
Fifo *f;
int fd;
f->fd = -1;
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = f;
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ .data.ptr = f,
+ };
+
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
r = -errno;
fifo_free(f);
cursor);
}
- return process_journal_input(u, 1 + !!after_cursor);
+ return process_journal_input(u, !!after_cursor);
}
break;
case ARG_FILE:
- r = glob_extend(&arg_file, optarg);
+ r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
break;
#include <lz4frame.h>
#endif
+#if HAVE_ZSTD
+#include <zstd.h>
+#include <zstd_errors.h>
+#endif
+
#include "alloc-util.h"
#include "compress.h"
#include "fd-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
#endif
+#if HAVE_ZSTD
+DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_CCtx *, ZSTD_freeCCtx);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_DCtx *, ZSTD_freeDCtx);
+
+static int zstd_ret_to_errno(size_t ret) {
+ switch (ZSTD_getErrorCode(ret)) {
+ case ZSTD_error_dstSize_tooSmall:
+ return -ENOBUFS;
+ case ZSTD_error_memory_allocation:
+ return -ENOMEM;
+ default:
+ return -EBADMSG;
+ }
+}
+#endif
+
#define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = {
#endif
}
+int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
+#if HAVE_ZSTD
+ _cleanup_(ZSTD_freeCCtxp) ZSTD_CCtx *cctx = NULL;
+ _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
+ size_t in_allocsize, out_allocsize;
+ size_t z;
+ uint64_t left = max_bytes, in_bytes = 0;
+ /* This can be used in the future to add uncompressed size to the header */
+ uint64_t in_totalsize = 0;
+
+ assert(fdf >= 0);
+ assert(fdt >= 0);
+
+ /* Create the context and buffers */
+ in_allocsize = ZSTD_CStreamInSize();
+ out_allocsize = ZSTD_CStreamOutSize();
+ in_buff = malloc(in_allocsize);
+ out_buff = malloc(out_allocsize);
+ cctx = ZSTD_createCCtx();
+ if (!cctx || !out_buff || !in_buff)
+ return -ENOMEM;
+
+ if (in_totalsize) {
+ z = ZSTD_CCtx_setPledgedSrcSize(cctx, in_totalsize);
+ if (z)
+ log_debug("Failed to enable ZSTD input size, ignoring: %s", ZSTD_getErrorName(z));
+ }
+ z = ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1);
+ if (ZSTD_isError(z))
+ log_debug("Failed to enable ZSTD checksum, ignoring: %s", ZSTD_getErrorName(z));
+
+ /* This loop read from the input file, compresses that entire chunk,
+ * and writes all output produced to the output file.
+ */
+ for (;;) {
+ bool is_last_chunk;
+ ZSTD_inBuffer input = {
+ .src = in_buff,
+ .size = 0,
+ .pos = 0
+ };
+ ssize_t red;
+
+ red = loop_read(fdf, in_buff, in_allocsize, true);
+ if (red < 0)
+ return red;
+ is_last_chunk = red == 0;
+
+ in_bytes += (size_t) red;
+ input.size = (size_t) red;
+
+ for (bool finished = false; !finished;) {
+ ZSTD_outBuffer output = {
+ .dst = out_buff,
+ .size = out_allocsize,
+ .pos = 0
+ };
+ size_t remaining;
+ ssize_t wrote;
+
+ /* Compress into the output buffer and write all of the
+ * output to the file so we can reuse the buffer next
+ * iteration.
+ */
+ remaining = ZSTD_compressStream2(
+ cctx, &output, &input,
+ is_last_chunk ? ZSTD_e_end : ZSTD_e_continue);
+
+ if (ZSTD_isError(remaining)) {
+ log_debug("ZSTD encoder failed: %s", ZSTD_getErrorName(remaining));
+ return zstd_ret_to_errno(remaining);
+ }
+
+ if (left < output.pos)
+ return -EFBIG;
+
+ wrote = loop_write(fdt, output.dst, output.pos, 1);
+ if (wrote < 0)
+ return wrote;
+
+ left -= output.pos;
+
+ /* If we're on the last chunk we're finished when zstd
+ * returns 0, which means its consumed all the input AND
+ * finished the frame. Otherwise, we're finished when
+ * we've consumed all the input.
+ */
+ finished = is_last_chunk ? (remaining == 0) : (input.pos == input.size);
+ }
+
+ /* zstd only returns 0 when the input is completely consumed */
+ assert(input.pos == input.size);
+ if (is_last_chunk)
+ break;
+ }
+
+ log_debug(
+ "ZSTD compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+ in_bytes,
+ max_bytes - left,
+ (double) (max_bytes - left) / in_bytes * 100);
+
+ return 0;
+#else
+ return -EPROTONOSUPPORT;
+#endif
+}
+
+int decompress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
+#if HAVE_ZSTD
+ _cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = NULL;
+ _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
+ size_t in_allocsize, out_allocsize;
+ size_t last_result = 0;
+ uint64_t left = max_bytes, in_bytes = 0;
+
+ assert(fdf >= 0);
+ assert(fdt >= 0);
+
+ /* Create the context and buffers */
+ in_allocsize = ZSTD_DStreamInSize();
+ out_allocsize = ZSTD_DStreamOutSize();
+ in_buff = malloc(in_allocsize);
+ out_buff = malloc(out_allocsize);
+ dctx = ZSTD_createDCtx();
+ if (!dctx || !out_buff || !in_buff)
+ return -ENOMEM;
+
+ /* This loop assumes that the input file is one or more concatenated
+ * zstd streams. This example won't work if there is trailing non-zstd
+ * data at the end, but streaming decompression in general handles this
+ * case. ZSTD_decompressStream() returns 0 exactly when the frame is
+ * completed, and doesn't consume input after the frame.
+ */
+ for (;;) {
+ bool has_error = false;
+ ZSTD_inBuffer input = {
+ .src = in_buff,
+ .size = 0,
+ .pos = 0
+ };
+ ssize_t red;
+
+ red = loop_read(fdf, in_buff, in_allocsize, true);
+ if (red < 0)
+ return red;
+ if (red == 0)
+ break;
+
+ in_bytes += (size_t) red;
+ input.size = (size_t) red;
+ input.pos = 0;
+
+ /* Given a valid frame, zstd won't consume the last byte of the
+ * frame until it has flushed all of the decompressed data of
+ * the frame. So input.pos < input.size means frame is not done
+ * or there is still output available.
+ */
+ while (input.pos < input.size) {
+ ZSTD_outBuffer output = {
+ .dst = out_buff,
+ .size = out_allocsize,
+ .pos = 0
+ };
+ ssize_t wrote;
+ /* The return code is zero if the frame is complete, but
+ * there may be multiple frames concatenated together.
+ * Zstd will automatically reset the context when a
+ * frame is complete. Still, calling ZSTD_DCtx_reset()
+ * can be useful to reset the context to a clean state,
+ * for instance if the last decompression call returned
+ * an error.
+ */
+ last_result = ZSTD_decompressStream(dctx, &output, &input);
+ if (ZSTD_isError(last_result)) {
+ has_error = true;
+ break;
+ }
+
+ if (left < output.pos)
+ return -EFBIG;
+
+ wrote = loop_write(fdt, output.dst, output.pos, 1);
+ if (wrote < 0)
+ return wrote;
+
+ left -= output.pos;
+ }
+ if (has_error)
+ break;
+ }
+
+ if (in_bytes == 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "ZSTD decoder failed: no data read");
+
+ if (last_result != 0) {
+ /* The last return value from ZSTD_decompressStream did not end
+ * on a frame, but we reached the end of the file! We assume
+ * this is an error, and the input was truncated.
+ */
+ log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(last_result));
+ return zstd_ret_to_errno(last_result);
+ }
+
+ log_debug(
+ "ZSTD decompression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+ in_bytes,
+ max_bytes - left,
+ (double) (max_bytes - left) / in_bytes * 100);
+ return 0;
+#else
+ log_debug("Cannot decompress file. Compiled without ZSTD support.");
+ return -EPROTONOSUPPORT;
+#endif
+}
+
int decompress_stream(const char *filename, int fdf, int fdt, uint64_t max_bytes) {
if (endswith(filename, ".lz4"))
return decompress_stream_lz4(fdf, fdt, max_bytes);
else if (endswith(filename, ".xz"))
return decompress_stream_xz(fdf, fdt, max_bytes);
+ else if (endswith(filename, ".zst"))
+ return decompress_stream_zstd(fdf, fdt, max_bytes);
else
return -EPROTONOSUPPORT;
}
int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes);
int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes);
+int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes);
int decompress_stream_xz(int fdf, int fdt, uint64_t max_size);
int decompress_stream_lz4(int fdf, int fdt, uint64_t max_size);
+int decompress_stream_zstd(int fdf, int fdt, uint64_t max_size);
-#if HAVE_LZ4
+#if HAVE_ZSTD
+# define compress_stream compress_stream_zstd
+# define COMPRESSED_EXT ".zst"
+#elif HAVE_LZ4
# define compress_stream compress_stream_lz4
# define COMPRESSED_EXT ".lz4"
#else
static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
gcry_mpi_t h;
- unsigned len;
+ _unused_ unsigned len;
assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
len = (gcry_mpi_get_nbits(h) + 7) / 8;
#include "errno-util.h"
#include "fd-util.h"
#include "io-util.h"
+#include "fileio.h"
#include "memfd-util.h"
#include "socket-util.h"
#include "stdio-util.h"
}
_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
-
- /* FIXME: Instead of limiting things to LINE_MAX we could do a
- C99 variable-length array on the stack here in a loop. */
-
- char buffer[8 + LINE_MAX], p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+ char p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+ char sbuf[LINE_MAX + 8] = "MESSAGE=";
struct iovec iov[2];
+ int len;
+ va_list aq;
+ char *buffer = sbuf;
assert_return(priority >= 0, -EINVAL);
assert_return(priority <= 7, -EINVAL);
xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
- memcpy(buffer, "MESSAGE=", 8);
- vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
+ va_copy(aq, ap);
+ len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
+ va_end(aq);
+
+ if (len >= (int)LONG_LINE_MAX - 8)
+ return -ENOBUFS;
+
+ /* Allocate large buffer to accomodate big message */
+ if (len >= LINE_MAX) {
+ int rlen;
+ buffer = alloca(len + 9);
+ memcpy(buffer, "MESSAGE=", 8);
+ rlen = vsnprintf(buffer + 8, len + 1, format, ap);
+ assert(len == rlen);
+ }
/* Strip trailing whitespace, keep prefix whitespace. */
(void) strstrip(buffer);
/* Suppress empty lines */
- if (isempty(buffer+8))
+ if (isempty(buffer + 8))
return 0;
iov[0] = IOVEC_MAKE_STRING(buffer);
}
_public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) {
- char buffer[8 + LINE_MAX], p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+ char p[STRLEN("PRIORITY=") + DECIMAL_STR_MAX(int) + 1];
+ char sbuf[LINE_MAX + 8] = "MESSAGE=";
struct iovec iov[5];
char *f;
+ int len;
+ char *buffer = sbuf;
+ va_list aq;
assert_return(priority >= 0, -EINVAL);
assert_return(priority <= 7, -EINVAL);
xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
- memcpy(buffer, "MESSAGE=", 8);
- vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap);
+ va_copy(aq, ap);
+ len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
+ va_end(aq);
+
+ if (len >= (int)LONG_LINE_MAX - 8)
+ return -ENOBUFS;
+
+ /* Allocate large buffer to accomodate big message */
+ if (len >= LINE_MAX) {
+ int rlen;
+ buffer = alloca(len + 9);
+ memcpy(buffer, "MESSAGE=", 8);
+ rlen = vsnprintf(buffer + 8, len + 1, format, ap);
+ assert(len == rlen);
+ }
/* Strip trailing whitespace, keep prefixing whitespace */
(void) strstrip(buffer);
/* Suppress empty lines */
- if (isempty(buffer+8))
+ if (isempty(buffer + 8))
return 0;
/* func is initialized from __func__ which is not a macro, but
* STDIN. To avoid confusion we hence don't document this feature. */
arg_file_stdin = true;
else {
- r = glob_extend(&arg_file, optarg);
+ r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
}
int fd = -1, r;
sd_id128_t machine, boot;
char *p = NULL, *k = NULL;
- struct FSSHeader h;
uint64_t n;
struct stat st;
if (r < 0)
log_warning_errno(r, "Failed to set file attributes: %m");
- zero(h);
+ struct FSSHeader h = {
+ .machine_id = machine,
+ .boot_id = boot,
+ .header_size = htole64(sizeof(h)),
+ .start_usec = htole64(n * arg_interval),
+ .interval_usec = htole64(arg_interval),
+ .fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR),
+ .fsprg_state_size = htole64(state_size),
+ };
+
memcpy(h.signature, "KSHHRHLP", 8);
- h.machine_id = machine;
- h.boot_id = boot;
- h.header_size = htole64(sizeof(h));
- h.start_usec = htole64(n * arg_interval);
- h.interval_usec = htole64(arg_interval);
- h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
- h.fsprg_state_size = htole64(state_size);
r = loop_write(fd, &h, sizeof(h), false);
if (r < 0) {
int *fds = NULL, v = 0;
size_t n_fds = 0;
- union {
- struct cmsghdr cmsghdr;
-
- /* We use NAME_MAX space for the SELinux label
- * here. The kernel currently enforces no
- * limit, but according to suggestions from
- * the SELinux people this will change and it
- * will probably be identical to NAME_MAX. For
- * now we use that, but this should be updated
- * one day when the final limit is known. */
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(struct timeval)) +
- CMSG_SPACE(sizeof(int)) + /* fd */
- CMSG_SPACE(NAME_MAX)]; /* selinux label */
- } control = {};
+ /* We use NAME_MAX space for the SELinux label here. The kernel currently enforces no limit, but
+ * according to suggestions from the SELinux people this will change and it will probably be
+ * identical to NAME_MAX. For now we use that, but this should be updated one day when the final
+ * limit is known. */
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(struct timeval)) +
+ CMSG_SPACE(sizeof(int)) + /* fd */
+ CMSG_SPACE(NAME_MAX) /* selinux label */) control;
union sockaddr_union sa = {};
iovec = IOVEC_MAKE(s->buffer, s->buffer_size - 1); /* Leave room for trailing NUL we add later */
- n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (IN_SET(errno, EINTR, EAGAIN))
- return 0;
-
- return log_error_errno(errno, "recvmsg() failed: %m");
+ n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (IN_SET(n, -EINTR, -EAGAIN))
+ return 0;
+ if (n == -EXFULL) {
+ log_warning("Got message with truncated control data (too many fds sent?), ignoring.");
+ return 0;
}
+ if (n < 0)
+ return log_error_errno(n, "recvmsg() failed: %m");
CMSG_FOREACH(cmsg, &msghdr)
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+ assert(!ucred);
ucred = (struct ucred*) CMSG_DATA(cmsg);
- else if (cmsg->cmsg_level == SOL_SOCKET &&
+ } else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_SECURITY) {
+ assert(!label);
label = (char*) CMSG_DATA(cmsg);
label_len = cmsg->cmsg_len - CMSG_LEN(0);
} else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMP &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) {
+ assert(!tv);
tv = (struct timeval*) CMSG_DATA(cmsg);
- else if (cmsg->cmsg_level == SOL_SOCKET &&
+ } else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
+ assert(!fds);
fds = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
}
r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
if (r < 0)
- return log_error_errno(r, "Failed to adjust priority of host name event source: %m");
+ return log_error_errno(r, "Failed to adjust priority of hostname event source: %m");
return 0;
}
LINE_BREAK_NUL,
LINE_BREAK_LINE_MAX,
LINE_BREAK_EOF,
+ LINE_BREAK_PID_CHANGE,
+ _LINE_BREAK_MAX,
+ _LINE_BREAK_INVALID = -1,
} LineBreak;
struct StdoutStream {
return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
}
-static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) {
+static int stdout_stream_log(
+ StdoutStream *s,
+ const char *p,
+ LineBreak line_break) {
+
struct iovec *iovec;
int priority;
char syslog_priority[] = "PRIORITY=\0";
assert(s);
assert(p);
+ assert(line_break >= 0);
+ assert(line_break < _LINE_BREAK_MAX);
+
if (s->context)
(void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY);
else if (pid_is_valid(s->ucred.pid)) {
iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
}
- if (line_break != LINE_BREAK_NEWLINE) {
- const char *c;
+ static const char * const line_break_field_table[_LINE_BREAK_MAX] = {
+ [LINE_BREAK_NEWLINE] = NULL, /* Do not add field if traditional newline */
+ [LINE_BREAK_NUL] = "_LINE_BREAK=nul",
+ [LINE_BREAK_LINE_MAX] = "_LINE_BREAK=line-max",
+ [LINE_BREAK_EOF] = "_LINE_BREAK=eof",
+ [LINE_BREAK_PID_CHANGE] = "_LINE_BREAK=pid-change",
+ };
- /* If this log message was generated due to an uncommon line break then mention this in the log
- * entry */
+ const char *c = line_break_field_table[line_break];
- c = line_break == LINE_BREAK_NUL ? "_LINE_BREAK=nul" :
- line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" :
- "_LINE_BREAK=eof";
+ /* If this log message was generated due to an uncommon line break then mention this in the log
+ * entry */
+ if (c)
iovec[n++] = IOVEC_MAKE_STRING(c);
- }
message = strjoin("MESSAGE=", p);
if (message)
}
static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
- int r;
char *orig;
+ int r;
assert(s);
assert(p);
p = strstrip(p);
/* line breaks by NUL, line max length or EOF are not permissible during the negotiation part of the protocol */
- if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING) {
- log_warning("Control protocol line not properly terminated.");
- return -EINVAL;
- }
+ if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Control protocol line not properly terminated.");
switch (s->state) {
assert_not_reached("Unknown stream state");
}
-static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
- char *p;
- size_t remaining;
+static int stdout_stream_found(
+ StdoutStream *s,
+ char *p,
+ size_t l,
+ LineBreak line_break) {
+
+ char saved;
int r;
assert(s);
+ assert(p);
+
+ /* Let's NUL terminate the specified buffer for this call, and revert back afterwards */
+ saved = p[l];
+ p[l] = 0;
+ r = stdout_stream_line(s, p, line_break);
+ p[l] = saved;
+
+ return r;
+}
+
+static int stdout_stream_scan(
+ StdoutStream *s,
+ char *p,
+ size_t remaining,
+ LineBreak force_flush,
+ size_t *ret_consumed) {
- p = s->buffer;
- remaining = s->length;
+ size_t consumed = 0;
+ int r;
- /* XXX: This function does nothing if (s->length == 0) */
+ assert(s);
+ assert(p);
for (;;) {
LineBreak line_break;
- size_t skip;
+ size_t skip, found;
char *end1, *end2;
end1 = memchr(p, '\n', remaining);
if (end2) {
/* We found a NUL terminator */
- skip = end2 - p + 1;
+ found = end2 - p;
+ skip = found + 1;
line_break = LINE_BREAK_NUL;
} else if (end1) {
/* We found a \n terminator */
- *end1 = 0;
- skip = end1 - p + 1;
+ found = end1 - p;
+ skip = found + 1;
line_break = LINE_BREAK_NEWLINE;
} else if (remaining >= s->server->line_max) {
/* Force a line break after the maximum line length */
- *(p + s->server->line_max) = 0;
- skip = remaining;
+ found = skip = s->server->line_max;
line_break = LINE_BREAK_LINE_MAX;
} else
break;
- r = stdout_stream_line(s, p, line_break);
+ r = stdout_stream_found(s, p, found, line_break);
if (r < 0)
return r;
- remaining -= skip;
p += skip;
+ consumed += skip;
+ remaining -= skip;
}
- if (force_flush && remaining > 0) {
- p[remaining] = 0;
- r = stdout_stream_line(s, p, LINE_BREAK_EOF);
+ if (force_flush >= 0 && remaining > 0) {
+ r = stdout_stream_found(s, p, remaining, force_flush);
if (r < 0)
return r;
- p += remaining;
- remaining = 0;
+ consumed += remaining;
}
- if (p > s->buffer) {
- memmove(s->buffer, p, remaining);
- s->length = remaining;
- }
+ if (ret_consumed)
+ *ret_consumed = consumed;
return 0;
}
static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
StdoutStream *s = userdata;
- struct ucred *ucred = NULL;
- struct cmsghdr *cmsg;
+ size_t limit, consumed;
+ struct ucred *ucred;
struct iovec iovec;
- size_t limit;
ssize_t l;
+ char *p;
int r;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
- .msg_control = buf,
- .msg_controllen = sizeof(buf),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
};
assert(s);
goto terminate;
}
- /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */
- if (s->length + 1 >= s->allocated) {
+ /* If the buffer is almost full, add room for another 1K */
+ if (s->length + 512 >= s->allocated) {
if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) {
log_oom();
goto terminate;
/* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
* always leave room for a terminating NUL we might need to add. */
limit = MIN(s->allocated - 1, s->server->line_max);
-
+ assert(s->length <= limit);
iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length);
l = recvmsg(s->fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
cmsg_close_all(&msghdr);
if (l == 0) {
- stdout_stream_scan(s, true);
+ (void) stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_EOF, NULL);
goto terminate;
}
- CMSG_FOREACH(cmsg, &msghdr)
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
- ucred = (struct ucred *)CMSG_DATA(cmsg);
- break;
- }
-
- /* Invalidate the context if the pid of the sender changed.
- * This happens when a forked process inherits stdout / stderr
- * from a parent. In this case getpeercred returns the ucred
- * of the parent, which can be invalid if the parent has exited
- * in the meantime.
- */
+ /* Invalidate the context if the PID of the sender changed. This happens when a forked process
+ * inherits stdout/stderr from a parent. In this case getpeercred() returns the ucred of the parent,
+ * which can be invalid if the parent has exited in the meantime. */
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (ucred && ucred->pid != s->ucred.pid) {
- /* force out any previously half-written lines from a
- * different process, before we switch to the new ucred
- * structure for everything we just added */
- r = stdout_stream_scan(s, true);
+ /* Force out any previously half-written lines from a different process, before we switch to
+ * the new ucred structure for everything we just added */
+ r = stdout_stream_scan(s, s->buffer, s->length, /* force_flush = */ LINE_BREAK_PID_CHANGE, NULL);
if (r < 0)
goto terminate;
- s->ucred = *ucred;
- client_context_release(s->server, s->context);
- s->context = NULL;
+ s->context = client_context_release(s->server, s->context);
+
+ p = s->buffer + s->length;
+ } else {
+ p = s->buffer;
+ l += s->length;
}
- s->length += l;
- r = stdout_stream_scan(s, false);
+ /* Always copy in the new credentials */
+ if (ucred)
+ s->ucred = *ucred;
+
+ r = stdout_stream_scan(s, p, l, _LINE_BREAK_INVALID, &consumed);
if (r < 0)
goto terminate;
+ /* Move what wasn't consumed to the front of the buffer */
+ assert(consumed <= (size_t) l);
+ s->length = l - consumed;
+ memmove(s->buffer, p + consumed, s->length);
+
return 1;
terminate:
.msg_iovlen = n_iovec,
};
struct cmsghdr *cmsg;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
const char *j;
int r;
if (!m->last_unused || m->n_windows <= WINDOWS_MIN) {
/* Allocate a new window */
- w = new0(Window, 1);
+ w = new(Window, 1);
if (!w)
return NULL;
m->n_windows++;
/* Reuse an existing one */
w = m->last_unused;
window_unlink(w);
- zero(*w);
}
- w->cache = m;
- w->fd = f;
- w->prot = prot;
- w->keep_always = keep_always;
- w->offset = offset;
- w->size = size;
- w->ptr = ptr;
+ *w = (Window) {
+ .cache = m,
+ .fd = f,
+ .prot = prot,
+ .keep_always = keep_always,
+ .offset = offset,
+ .size = size,
+ .ptr = ptr,
+ };
LIST_PREPEND(by_fd, f->windows, w);
!((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
return 0;
- if (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
- dirname_has_namespace(dirname, j->namespace) > 0 ||
- (FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0)))
+ if (dirname &&
+ (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
+ dirname_has_namespace(dirname, j->namespace) > 0 ||
+ (FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0))))
return 0;
r = directory_open(j, path, &d);
int main(int argc, char **argv) {
test_audit_type();
+ return 0;
}
# define LZ4_OK -EPROTONOSUPPORT
#endif
+#define HUGE_SIZE (4096*1024)
+
typedef int (compress_blob_t)(const void *src, uint64_t src_size,
void *dst, size_t dst_alloc_size, size_t *dst_size);
typedef int (decompress_blob_t)(const void *src, uint64_t src_size,
typedef int (compress_stream_t)(int fdf, int fdt, uint64_t max_bytes);
typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
-#if HAVE_XZ || HAVE_LZ4
-static void test_compress_decompress(int compression,
- compress_blob_t compress,
- decompress_blob_t decompress,
- const char *data,
- size_t data_len,
- bool may_fail) {
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
+_unused_ static void test_compress_decompress(const char *compression,
+ compress_blob_t compress,
+ decompress_blob_t decompress,
+ const char *data,
+ size_t data_len,
+ bool may_fail) {
char compressed[512];
size_t csize, usize = 0;
_cleanup_free_ char *decompressed = NULL;
int r;
log_info("/* testing %s %s blob compression/decompression */",
- object_compressed_to_string(compression), data);
+ compression, data);
r = compress(data, data_len, compressed, sizeof(compressed), &csize);
if (r == -ENOBUFS) {
memzero(decompressed, usize);
}
-static void test_decompress_startswith(int compression,
- compress_blob_t compress,
- decompress_sw_t decompress_sw,
- const char *data,
- size_t data_len,
- bool may_fail) {
+_unused_ static void test_decompress_startswith(const char *compression,
+ compress_blob_t compress,
+ decompress_sw_t decompress_sw,
+ const char *data,
+ size_t data_len,
+ bool may_fail) {
char *compressed;
_cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL;
int r;
log_info("/* testing decompress_startswith with %s on %.20s text */",
- object_compressed_to_string(compression), data);
+ compression, data);
#define BUFSIZE_1 512
#define BUFSIZE_2 20000
assert_se(r > 0);
}
-static void test_decompress_startswith_short(int compression,
- compress_blob_t compress,
- decompress_sw_t decompress_sw) {
+_unused_ static void test_decompress_startswith_short(const char *compression,
+ compress_blob_t compress,
+ decompress_sw_t decompress_sw) {
#define TEXT "HUGE=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
size_t i, csize;
int r;
- log_info("/* %s with %s */", __func__, object_compressed_to_string(compression));
+ log_info("/* %s with %s */", __func__, compression);
r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize);
assert_se(r == 0);
}
}
-static void test_compress_stream(int compression,
- const char* cat,
- compress_stream_t compress,
- decompress_stream_t decompress,
- const char *srcfile) {
+_unused_ static void test_compress_stream(const char *compression,
+ const char *cat,
+ compress_stream_t compress,
+ decompress_stream_t decompress,
+ const char *srcfile) {
_cleanup_close_ int src = -1, dst = -1, dst2 = -1;
_cleanup_(unlink_tempfilep) char
return;
}
- log_debug("/* testing %s compression */",
- object_compressed_to_string(compression));
+ log_debug("/* testing %s compression */", compression);
log_debug("/* create source from %s */", srcfile);
int r;
_cleanup_free_ char *huge = NULL;
-#define HUGE_SIZE (4096*1024)
assert_se(huge = malloc(HUGE_SIZE));
- memset(huge, 'x', HUGE_SIZE);
- memcpy(huge, "HUGE=", 5);
+ memcpy(huge, "HUGE=", STRLEN("HUGE="));
+ memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+ huge[HUGE_SIZE - 1] = '\0';
r = LZ4_compress_default(huge, buf, HUGE_SIZE, buf_size);
assert_se(r >= 0);
#endif
int main(int argc, char *argv[]) {
-#if HAVE_XZ || HAVE_LZ4
- const char text[] =
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
+ _unused_ const char text[] =
"text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
"foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
char data[512] = "random\0";
- char huge[4096*1024];
- memset(huge, 'x', sizeof(huge));
- memcpy(huge, "HUGE=", 5);
- char_array_0(huge);
+ _cleanup_free_ char *huge = NULL;
+
+ assert_se(huge = malloc(HUGE_SIZE));
+ memcpy(huge, "HUGE=", STRLEN("HUGE="));
+ memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+ huge[HUGE_SIZE - 1] = '\0';
test_setup_logging(LOG_DEBUG);
random_bytes(data + 7, sizeof(data) - 7);
#if HAVE_XZ
- test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+ test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
text, sizeof(text), false);
- test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+ test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
data, sizeof(data), true);
- test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+ test_decompress_startswith("XZ",
compress_blob_xz, decompress_startswith_xz,
text, sizeof(text), false);
- test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+ test_decompress_startswith("XZ",
compress_blob_xz, decompress_startswith_xz,
data, sizeof(data), true);
- test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+ test_decompress_startswith("XZ",
compress_blob_xz, decompress_startswith_xz,
- huge, sizeof(huge), true);
+ huge, HUGE_SIZE, true);
- test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
+ test_compress_stream("XZ", "xzcat",
compress_stream_xz, decompress_stream_xz, srcfile);
- test_decompress_startswith_short(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz);
+ test_decompress_startswith_short("XZ", compress_blob_xz, decompress_startswith_xz);
#else
log_info("/* XZ test skipped */");
#endif
#if HAVE_LZ4
- test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+ test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
text, sizeof(text), false);
- test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+ test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
data, sizeof(data), true);
- test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+ test_decompress_startswith("LZ4",
compress_blob_lz4, decompress_startswith_lz4,
text, sizeof(text), false);
- test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+ test_decompress_startswith("LZ4",
compress_blob_lz4, decompress_startswith_lz4,
data, sizeof(data), true);
- test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+ test_decompress_startswith("LZ4",
compress_blob_lz4, decompress_startswith_lz4,
- huge, sizeof(huge), true);
+ huge, HUGE_SIZE, true);
- test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
+ test_compress_stream("LZ4", "lz4cat",
compress_stream_lz4, decompress_stream_lz4, srcfile);
test_lz4_decompress_partial();
- test_decompress_startswith_short(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4);
+ test_decompress_startswith_short("LZ4", compress_blob_lz4, decompress_startswith_lz4);
#else
log_info("/* LZ4 test skipped */");
#endif
+#if HAVE_ZSTD
+ test_compress_stream("ZSTD", "zstdcat",
+ compress_stream_zstd, decompress_stream_zstd, srcfile);
+#else
+ log_info("/* ZSTD test skipped */");
+#endif
+
return 0;
#else
- log_info("/* XZ and LZ4 tests skipped */");
+ log_info("/* XZ, LZ4 and ZSTD tests skipped */");
return EXIT_TEST_SKIP;
#endif
}
#include <unistd.h>
#include "sd-journal.h"
-
+#include "fileio.h"
#include "macro.h"
+#include "memory-util.h"
+
+static void test_journal_print(void) {
+ assert_se(sd_journal_print(LOG_INFO, "XXX") == 0);
+ assert_se(sd_journal_print(LOG_INFO, "%s", "YYY") == 0);
+ assert_se(sd_journal_print(LOG_INFO, "X%4094sY", "ZZZ") == 0);
+ assert_se(sd_journal_print(LOG_INFO, "X%*sY", LONG_LINE_MAX - 8 - 3, "ZZZ") == 0);
+ assert_se(sd_journal_print(LOG_INFO, "X%*sY", LONG_LINE_MAX - 8 - 2, "ZZZ") == -ENOBUFS);
+}
-int main(int argc, char *argv[]) {
- char huge[4096*1024];
+static void test_journal_send(void) {
+ _cleanup_free_ char *huge = NULL;
+
+#define HUGE_SIZE (4096*1024)
+ assert_se(huge = malloc(HUGE_SIZE));
/* utf-8 and non-utf-8, message-less and message-ful iovecs */
struct iovec graph1[] = {
assert_se(sd_journal_perror("") == 0);
- memset(huge, 'x', sizeof(huge));
- memcpy(huge, "HUGE=", 5);
- char_array_0(huge);
+ memcpy(huge, "HUGE=", STRLEN("HUGE="));
+ memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+ huge[HUGE_SIZE - 1] = '\0';
assert_se(sd_journal_send("MESSAGE=Huge field attached",
huge,
assert_se(sd_journal_sendv(graph2, 1) == 0);
assert_se(sd_journal_sendv(message1, 1) == 0);
assert_se(sd_journal_sendv(message2, 1) == 0);
+}
+
+int main(int argc, char *argv[]) {
+ test_journal_print();
+ test_journal_send();
+ /* Sleep a bit to make it easy for journald to collect metadata. */
sleep(1);
return 0;
#include "udev-util.h"
#include "virt.h"
-#define SYSTEMD_PEN 43793
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
#include "time-util.h"
#include "unaligned.h"
+#define SYSTEMD_PEN 43793
+
typedef enum DUIDType {
DUID_TYPE_LLT = 1,
DUID_TYPE_EN = 2,
DHCP_RAW_OPTION_DATA_UINT32,
DHCP_RAW_OPTION_DATA_STRING,
DHCP_RAW_OPTION_DATA_IPV4ADDRESS,
+ DHCP_RAW_OPTION_DATA_IPV6ADDRESS,
_DHCP_RAW_OPTION_DATA_MAX,
_DHCP_RAW_OPTION_DATA_INVALID,
} DHCPRawOption;
char *timezone;
struct in_addr *ntp, *dns, *sip, *pop3_server, *smtp_server, *lpr_server;
- unsigned n_ntp, n_dns, n_sip, n_pop3_server, n_smtp_server, n_lpr_server;
+ size_t n_ntp, n_dns, n_sip, n_pop3_server, n_smtp_server, n_lpr_server;
OrderedHashmap *extra_options;
OrderedHashmap *vendor_options;
#include "macro.h"
#include "sparse-endian.h"
+typedef struct sd_dhcp6_option {
+ unsigned n_ref;
+
+ uint16_t option;
+ void *data;
+ size_t length;
+} sd_dhcp6_option;
+
+extern const struct hash_ops dhcp6_option_hash_ops;
+
/* Common option header */
typedef struct DHCP6Option {
be16_t code;
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class);
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue);
int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
#include "sd-dhcp6-client.h"
#include "alloc-util.h"
+#include "dhcp-identifier.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
return r;
}
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) {
+ _cleanup_free_ uint8_t *p = NULL;
+ size_t total = 0, offset = 0;
+ char **s;
+
+ assert_return(buf && *buf && buflen && user_class, -EINVAL);
+
+ STRV_FOREACH(s, user_class) {
+ size_t len = strlen(*s);
+ uint8_t *q;
+
+ if (len > 0xffff)
+ return -ENAMETOOLONG;
+ q = realloc(p, total + len + 2);
+ if (!q)
+ return -ENOMEM;
+
+ p = q;
+
+ unaligned_write_be16(&p[offset], len);
+ memcpy(&p[offset + 2], *s, len);
+
+ offset += 2 + len;
+ total += 2 + len;
+ }
+
+ return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
+}
+
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) {
+ _cleanup_free_ uint8_t *p = NULL;
+ uint32_t enterprise_identifier;
+ size_t total, offset;
+ char **s;
+
+ assert(buf);
+ assert(*buf);
+ assert(buflen);
+ assert(vendor_class);
+
+ enterprise_identifier = htobe32(SYSTEMD_PEN);
+
+ p = memdup(&enterprise_identifier, sizeof(enterprise_identifier));
+ if (!p)
+ return -ENOMEM;
+
+ total = sizeof(enterprise_identifier);
+ offset = total;
+
+ STRV_FOREACH(s, vendor_class) {
+ size_t len = strlen(*s);
+ uint8_t *q;
+
+ q = realloc(p, total + len + 2);
+ if (!q)
+ return -ENOMEM;
+
+ p = q;
+
+ unaligned_write_be16(&p[offset], len);
+ memcpy(&p[offset + 2], *s, len);
+
+ offset += 2 + len;
+ total += 2 + len;
+ }
+
+ return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
+}
+
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
DHCP6Option *option = (DHCP6Option *)buf;
size_t i = sizeof(*option) + sizeof(pd->ia_pd);
return idx;
}
+
+static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) {
+ if (!i)
+ return NULL;
+
+ free(i->data);
+ return mfree(i);
+}
+
+int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, sd_dhcp6_option **ret) {
+ assert_return(ret, -EINVAL);
+ assert_return(length == 0 || data, -EINVAL);
+
+ _cleanup_free_ void *q = memdup(data, length);
+ if (!q)
+ return -ENOMEM;
+
+ sd_dhcp6_option *p = new(sd_dhcp6_option, 1);
+ if (!p)
+ return -ENOMEM;
+
+ *p = (sd_dhcp6_option) {
+ .n_ref = 1,
+ .option = option,
+ .length = length,
+ .data = TAKE_PTR(q),
+ };
+
+ *ret = p;
+ return 0;
+}
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_option, sd_dhcp6_option, dhcp6_option_free);
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+ dhcp6_option_hash_ops,
+ void,
+ trivial_hash_func,
+ trivial_compare_func,
+ sd_dhcp6_option,
+ sd_dhcp6_option_unref);
int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
triple_timestamp *timestamp) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int)) + /* ttl */
- CMSG_SPACE(sizeof(struct timeval))];
- } control = {};
+
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int)) + /* ttl */
+ CMSG_SPACE(sizeof(struct timeval))) control;
struct iovec iov = {};
union sockaddr_union sa = {};
struct msghdr msg = {
iov = IOVEC_MAKE(buffer, size);
- len = recvmsg(fd, &msg, MSG_DONTWAIT);
+ len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
if (len < 0)
- return -errno;
+ return (int) len;
if ((size_t) len != size)
return -EINVAL;
char *mudurl;
char **user_class;
uint32_t mtu;
+ uint32_t fallback_lease_lifetime;
uint32_t xid;
usec_t start_time;
uint64_t attempt;
return 0;
}
+int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
+ assert_return(client, -EINVAL);
+ assert_return(fallback_lease_lifetime > 0, -EINVAL);
+
+ client->fallback_lease_lifetime = fallback_lease_lifetime;
+
+ return 0;
+}
+
static int client_notify(sd_dhcp_client *client, int event) {
assert(client);
packet, len);
}
-static int client_send_discover(sd_dhcp_client *client) {
- _cleanup_free_ DHCPPacket *discover = NULL;
- size_t optoffset, optlen;
+static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) {
sd_dhcp_option *j;
Iterator i;
int r;
assert(client);
- assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
-
- r = client_message_init(client, &discover, DHCP_DISCOVER,
- &optlen, &optoffset);
- if (r < 0)
- return r;
-
- /* the client may suggest values for the network address
- and lease time in the DHCPDISCOVER message. The client may include
- the ’requested IP address’ option to suggest that a particular IP
- address be assigned, and may include the ’IP address lease time’
- option to suggest the lease time it would like.
- */
- /* RFC7844 section 3:
- SHOULD NOT contain any other option. */
- if (!client->anonymize && client->last_addr != INADDR_ANY) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
- 4, &client->last_addr);
- if (r < 0)
- return r;
- }
if (client->hostname) {
/* According to RFC 4702 "clients that send the Client FQDN option in
/* it is unclear from RFC 2131 if client should send hostname in
DHCPDISCOVER but dhclient does and so we do as well
*/
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_HOST_NAME,
strlen(client->hostname), client->hostname);
} else
- r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
+ r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset,
client->hostname);
if (r < 0)
return r;
}
if (client->vendor_class_identifier) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
strlen(client->vendor_class_identifier),
client->vendor_class_identifier);
}
if (client->mudurl) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_MUD_URL,
strlen(client->mudurl),
client->mudurl);
}
if (client->user_class) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_USER_CLASS,
strv_length(client->user_class),
client->user_class);
}
ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
j->option, j->length, j->data);
if (r < 0)
return r;
if (!ordered_hashmap_isempty(client->vendor_options)) {
r = dhcp_option_append(
- &discover->dhcp, optlen, &optoffset, 0,
+ &packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_VENDOR_SPECIFIC,
ordered_hashmap_size(client->vendor_options), client->vendor_options);
if (r < 0)
return r;
}
+
+ return 0;
+}
+
+static int client_send_discover(sd_dhcp_client *client) {
+ _cleanup_free_ DHCPPacket *discover = NULL;
+ size_t optoffset, optlen;
+ int r;
+
+ assert(client);
+ assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
+
+ r = client_message_init(client, &discover, DHCP_DISCOVER,
+ &optlen, &optoffset);
+ if (r < 0)
+ return r;
+
+ /* the client may suggest values for the network address
+ and lease time in the DHCPDISCOVER message. The client may include
+ the ’requested IP address’ option to suggest that a particular IP
+ address be assigned, and may include the ’IP address lease time’
+ option to suggest the lease time it would like.
+ */
+ /* RFC7844 section 3:
+ SHOULD NOT contain any other option. */
+ if (!client->anonymize && client->last_addr != INADDR_ANY) {
+ r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
+ 4, &client->last_addr);
+ if (r < 0)
+ return r;
+ }
+
+ r = client_append_common_discover_request_options(client, discover, &optoffset, optlen);
+ if (r < 0)
+ return r;
+
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return -EINVAL;
}
- if (client->hostname) {
- if (dns_name_is_single_label(client->hostname))
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_HOST_NAME,
- strlen(client->hostname), client->hostname);
- else
- r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
- client->hostname);
- if (r < 0)
- return r;
- }
-
- if (client->vendor_class_identifier) {
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
- strlen(client->vendor_class_identifier),
- client->vendor_class_identifier);
- if (r < 0)
- return r;
- }
-
- if (client->mudurl) {
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_MUD_URL,
- strlen(client->mudurl),
- client->mudurl);
- if (r < 0)
- return r;
- }
-
+ r = client_append_common_discover_request_options(client, request, &optoffset, optlen);
+ if (r < 0)
+ return r;
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
lease->next_server = offer->siaddr;
lease->address = offer->yiaddr;
+ if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
+ lease->lifetime = client->fallback_lease_lifetime;
+
if (lease->address == 0 ||
lease->server_address == 0 ||
lease->lifetime == 0) {
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPPacket *packet = NULL;
- uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct tpacket_auxdata))) control;
struct iovec iov = {};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
- .msg_control = cmsgbuf,
- .msg_controllen = sizeof(cmsgbuf),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
bool checksum = true;
iov = IOVEC_MAKE(packet, buflen);
- len = recvmsg(fd, &msg, 0);
- if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
- return 0;
-
- return log_dhcp_client_errno(client, errno,
- "Could not receive message from raw socket: %m");
- } else if ((size_t)len < sizeof(DHCPPacket))
+ len = recvmsg_safe(fd, &msg, 0);
+ if (IN_SET(len, -EAGAIN, -EINTR, -ENETDOWN))
return 0;
+ if (len < 0)
+ return log_dhcp_client_errno(client, len,
+ "Could not receive message from raw socket: %m");
- CMSG_FOREACH(cmsg, &msg)
- if (cmsg->cmsg_level == SOL_PACKET &&
- cmsg->cmsg_type == PACKET_AUXDATA &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
- struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
+ if ((size_t) len < sizeof(DHCPPacket))
+ return 0;
- checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
- break;
- }
+ cmsg = cmsg_find(&msg, SOL_PACKET, PACKET_AUXDATA, CMSG_LEN(sizeof(struct tpacket_auxdata)));
+ if (cmsg) {
+ struct tpacket_auxdata *aux = (struct tpacket_auxdata*) CMSG_DATA(cmsg);
+ checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
+ }
r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
if (r < 0)
case SD_DHCP_OPTION_HOST_NAME:
r = lease_parse_domain(option, len, &lease->hostname);
if (r < 0) {
- log_debug_errno(r, "Failed to parse host name, ignoring: %m");
+ log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
return 0;
}
* the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
* moreover, the server's own address may be in the pool, and is in that case reserved in order not to
* accidentally hand it out */
-int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size) {
+int sd_dhcp_server_configure_pool(
+ sd_dhcp_server *server,
+ const struct in_addr *address,
+ unsigned char prefixlen,
+ uint32_t offset,
+ uint32_t size) {
+
struct in_addr netmask_addr;
be32_t netmask;
uint32_t server_off, broadcast_off, size_max;
.iov_base = message,
.iov_len = len,
};
- uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
struct msghdr msg = {
.msg_name = &dest,
.msg_namelen = sizeof(dest.in),
.msg_iov = &iov,
.msg_iovlen = 1,
- .msg_control = cmsgbuf,
- .msg_controllen = sizeof(cmsgbuf),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
static int server_receive_message(sd_event_source *s, int fd,
uint32_t revents, void *userdata) {
_cleanup_free_ DHCPMessage *message = NULL;
- uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control;
sd_dhcp_server *server = userdata;
struct iovec iov = {};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
- .msg_control = cmsgbuf,
- .msg_controllen = sizeof(cmsgbuf),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
ssize_t buflen, len;
iov = IOVEC_MAKE(message, buflen);
- len = recvmsg(fd, &msg, 0);
- if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0;
-
- return -errno;
- }
- if ((size_t)len < sizeof(DHCPMessage))
+ len = recvmsg_safe(fd, &msg, 0);
+ if (IN_SET(len, -EAGAIN, -EINTR))
+ return 0;
+ if (len < 0)
+ return len;
+ if ((size_t) len < sizeof(DHCPMessage))
return 0;
CMSG_FOREACH(cmsg, &msg) {
sd_dhcp_server *server,
sd_dhcp_lease_info what,
const struct in_addr addresses[],
- unsigned n_addresses) {
+ size_t n_addresses) {
assert_return(server, -EINVAL);
assert_return(addresses || n_addresses == 0, -EINVAL);
struct in_addr **a;
- unsigned *n_a;
+ size_t *n_a;
switch (what) {
case SD_DHCP_LEASE_DNS_SERVERS:
return 1;
}
-int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
+int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n) {
return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_DNS_SERVERS, dns, n);
}
-int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
+int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n) {
return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_NTP_SERVERS, ntp, n);
}
-int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n) {
+int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n) {
return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SIP_SERVERS, sip, n);
}
-int sd_dhcp_server_set_pop3_server(sd_dhcp_server *server, const struct in_addr pop3[], unsigned n) {
+int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3[], size_t n) {
return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_POP3_SERVERS, pop3, n);
}
-int sd_dhcp_server_set_smtp_server(sd_dhcp_server *server, const struct in_addr smtp[], unsigned n) {
+int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[], size_t n) {
return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SMTP_SERVERS, smtp, n);
}
-int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], unsigned n) {
+int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n) {
return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_LPR_SERVERS, lpr, n);
}
size_t req_opts_len;
char *fqdn;
char *mudurl;
+ char **user_class;
+ char **vendor_class;
sd_event_source *receive_message;
usec_t retransmit_time;
uint8_t retransmit_count;
size_t duid_len;
usec_t information_request_time_usec;
usec_t information_refresh_time_usec;
+ OrderedHashmap *extra_options;
};
static const uint16_t default_req_opts[] = {
r = dhcp_validate_duid_len(duid_type, duid_len, false);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
- log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type);
+
+ log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
}
client->duid.type = htobe16(duid_type);
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
- switch(option) {
-
- case SD_DHCP6_OPTION_DNS_SERVERS:
- case SD_DHCP6_OPTION_DOMAIN_LIST:
- case SD_DHCP6_OPTION_SNTP_SERVERS:
- case SD_DHCP6_OPTION_NTP_SERVER:
- case SD_DHCP6_OPTION_RAPID_COMMIT:
- break;
-
- default:
+ if (option <= 0 || option >= UINT8_MAX)
return -EINVAL;
- }
for (t = 0; t < client->req_opts_len; t++)
if (client->req_opts[t] == htobe16(option))
return 0;
}
-int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, char *mudurl) {
+int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) {
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
assert_return(mudurl, -EINVAL);
- assert_return(strlen(mudurl) <= 255, -EINVAL);
+ assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL);
assert_return(http_url_is_valid(mudurl), -EINVAL);
return free_and_strdup(&client->mudurl, mudurl);
}
+int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
+ _cleanup_strv_free_ char **s = NULL;
+ char **p;
+
+ assert_return(client, -EINVAL);
+ assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+
+ assert_return(user_class, -EINVAL);
+
+ STRV_FOREACH(p, user_class)
+ if (strlen(*p) > UINT16_MAX)
+ return -ENAMETOOLONG;
+
+ s = strv_copy(user_class);
+ if (!s)
+ return -ENOMEM;
+
+ client->user_class = TAKE_PTR(s);
+
+ return 0;
+}
+
+int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
+ _cleanup_strv_free_ char **s = NULL;
+ char **p;
+
+ assert_return(client, -EINVAL);
+ assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+ assert_return(vendor_class, -EINVAL);
+
+ STRV_FOREACH(p, vendor_class)
+ if (strlen(*p) > UINT8_MAX)
+ return -ENAMETOOLONG;
+
+ s = strv_copy(vendor_class);
+ if (!s)
+ return -ENOMEM;
+
+ client->vendor_class = TAKE_PTR(s);
+
+ return 0;
+}
+
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
assert_return(client, -EINVAL);
assert_return(delegation, -EINVAL);
return 0;
}
+int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) {
+ int r;
+
+ assert_return(client, -EINVAL);
+ assert_return(v, -EINVAL);
+
+ r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
+ if (r < 0)
+ return r;
+
+ sd_dhcp6_option_ref(v);
+ return 0;
+}
+
static void client_notify(sd_dhcp6_client *client, int event) {
assert(client);
_cleanup_free_ DHCP6Message *message = NULL;
struct in6_addr all_servers =
IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
+ struct sd_dhcp6_option *j;
size_t len, optlen = 512;
+ Iterator i;
uint8_t *opt;
int r;
usec_t elapsed_usec;
return r;
}
+ if (client->user_class) {
+ r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
+ if (r < 0)
+ return r;
+ }
+
+ if (client->vendor_class) {
+ r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+ if (r < 0)
+ return r;
+ }
+
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
if (r < 0)
return r;
}
+ if (client->user_class) {
+ r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
+ if (r < 0)
+ return r;
+ }
+
+ if (client->vendor_class) {
+ r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+ if (r < 0)
+ return r;
+ }
+
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
if (r < 0)
return r;
}
+ if (client->user_class) {
+ r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class);
+ if (r < 0)
+ return r;
+ }
+
+ if (client->vendor_class) {
+ r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
+ if (r < 0)
+ return r;
+ }
+
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
if (r < 0)
if (r < 0)
return r;
+ ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
+ r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data);
+ if (r < 0)
+ return r;
+ }
+
r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
len - optlen);
if (r < 0)
free(client->req_opts);
free(client->fqdn);
free(client->mudurl);
+
+ ordered_hashmap_free(client->extra_options);
+ strv_free(client->user_class);
+ strv_free(client->vendor_class);
+
return mfree(client);
}
cur->valid_until = valid_until;
cur->preferred_until = preferred_until;
- log_radv("%s prefix %s/%u preferred %s valid %s",
- cur? "Updated": "Added",
+ log_radv("Updated prefix %s/%u preferred %s valid %s",
addr_p, p->opt.prefixlen,
format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
preferred, USEC_PER_SEC),
if (valid_until == USEC_INFINITY)
return -EOVERFLOW;
- log_radv("%s route prefix %s/%u valid %s",
- cur? "Updated": "Added",
+ log_radv("Updated route prefix %s/%u valid %s",
strempty(pretty), p->opt.prefixlen,
format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX, valid, USEC_PER_SEC));
assert_se(sd_dhcp6_client_set_fqdn(client, "~host") == -EINVAL);
assert_se(sd_dhcp6_client_set_fqdn(client, "~host.domain") == -EINVAL);
- assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == -EINVAL);
+ assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
- assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
+ assert_se(sd_dhcp6_client_set_request_option(client, 10) == 0);
assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
v = 0;
test_dhcp_lease_parse_search_domains_no_data();
test_dhcp_lease_parse_search_domains_loops();
test_dhcp_lease_parse_search_domains_wrong_len();
+ return 0;
}
#define BUS_ERROR_DISK_FULL "org.freedesktop.systemd1.DiskFull"
#define BUS_ERROR_NOTHING_TO_CLEAN "org.freedesktop.systemd1.NothingToClean"
#define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy"
+#define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive"
#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"
#include "memory-util.h"
#include "string-util.h"
+#define BUS_INTROSPECT_DOCTYPE \
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+
+#define BUS_INTROSPECT_INTERFACE_PEER \
+ " <interface name=\"org.freedesktop.DBus.Peer\">\n" \
+ " <method name=\"Ping\"/>\n" \
+ " <method name=\"GetMachineId\">\n" \
+ " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE \
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
+ " <method name=\"Introspect\">\n" \
+ " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_PROPERTIES \
+ " <interface name=\"org.freedesktop.DBus.Properties\">\n" \
+ " <method name=\"Get\">\n" \
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \
+ " </method>\n" \
+ " <method name=\"GetAll\">\n" \
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
+ " </method>\n" \
+ " <method name=\"Set\">\n" \
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
+ " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \
+ " </method>\n" \
+ " <signal name=\"PropertiesChanged\">\n" \
+ " <arg type=\"s\" name=\"interface\"/>\n" \
+ " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \
+ " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \
+ " </signal>\n" \
+ " </interface>\n"
+
+#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER \
+ " <interface name=\"org.freedesktop.DBus.ObjectManager\">\n" \
+ " <method name=\"GetManagedObjects\">\n" \
+ " <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <signal name=\"InterfacesAdded\">\n" \
+ " <arg type=\"o\" name=\"object_path\"/>\n" \
+ " <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
+ " </signal>\n" \
+ " <signal name=\"InterfacesRemoved\">\n" \
+ " <arg type=\"o\" name=\"object_path\"/>\n" \
+ " <arg type=\"as\" name=\"interfaces\"/>\n" \
+ " </signal>\n" \
+ " </interface>\n"
+
int introspect_begin(struct introspect *i, bool trusted) {
assert(i);
- zero(*i);
- i->trusted = trusted;
+ *i = (struct introspect) {
+ .trusted = trusted,
+ };
i->f = open_memstream_unlocked(&i->introspection, &i->size);
if (!i->f)
return 0;
}
+static int set_interface_name(struct introspect *intro, const char *interface_name) {
+ if (streq_ptr(intro->interface_name, interface_name))
+ return 0;
+
+ if (intro->interface_name)
+ fputs(" </interface>\n", intro->f);
+
+ if (interface_name)
+ fprintf(intro->f, " <interface name=\"%s\">\n", interface_name);
+
+ return free_and_strdup(&intro->interface_name, interface_name);
+}
+
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix) {
char *node;
assert(i);
assert(prefix);
+ assert_se(set_interface_name(i, NULL) >= 0);
+
while ((node = set_steal_first(s))) {
const char *e;
}
}
-int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
+int introspect_write_interface(
+ struct introspect *i,
+ const char *interface_name,
+ const sd_bus_vtable *v) {
+
const sd_bus_vtable *vtable = v;
const char *names = "";
+ int r;
assert(i);
+ assert(interface_name);
assert(v);
+ r = set_interface_name(i, interface_name);
+ if (r < 0)
+ return r;
+
for (; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) {
/* Ignore methods, signals and properties that are
assert(i);
+ assert_se(set_interface_name(i, NULL) >= 0);
+
fputs("</node>\n", i->f);
r = fflush_and_check(i->f);
/* Normally introspect_finish() does all the work, this is just a backup for error paths */
safe_fclose(i->f);
+ free(i->interface_name);
free(i->introspection);
}
struct introspect {
FILE *f;
+ char *interface_name;
char *introspection;
size_t size;
bool trusted;
int introspect_begin(struct introspect *i, bool trusted);
int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
-int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
+int introspect_write_interface(
+ struct introspect *i,
+ const char *interface_name,
+ const sd_bus_vtable *v);
int introspect_finish(struct introspect *i, char **ret);
void introspect_free(struct introspect *i);
if (!IN_SET(h->version, 1, 2))
return -EBADMSG;
- if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
+ if (h->type <= _SD_BUS_MESSAGE_TYPE_INVALID || h->type >= _SD_BUS_MESSAGE_TYPE_MAX)
return -EBADMSG;
if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(bus->state != BUS_UNSET, -ENOTCONN);
assert_return(m, -EINVAL);
- assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
+ assert_return(type > _SD_BUS_MESSAGE_TYPE_INVALID && type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
if (!t)
}
static void message_extend_containers(sd_bus_message *m, size_t expand) {
- struct bus_container *c;
-
assert(m);
if (expand <= 0)
return;
- /* Update counters */
- for (c = m->containers; c < m->containers + m->n_containers; c++) {
+ if (m->n_containers <= 0)
+ return;
+ /* Update counters */
+ for (struct bus_container *c = m->containers; c < m->containers + m->n_containers; c++)
if (c->array_size)
*c->array_size += expand;
- }
}
static void *message_extend_body(
if (r < 0)
return NULL;
} else {
- struct bus_container *c;
void *op;
size_t os, start_part, end_part;
}
/* Readjust pointers */
- for (c = m->containers; c < m->containers + m->n_containers; c++)
- c->array_size = adjust_pointer(c->array_size, op, os, part->data);
+ if (m->n_containers > 0)
+ for (struct bus_container *c = m->containers; c < m->containers + m->n_containers; c++)
+ c->array_size = adjust_pointer(c->array_size, op, os, part->data);
m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
}
* table */
m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
- /* Pull out the offset table for the fields array */
- sz = bus_gvariant_determine_word_size(m->fields_size, 0);
- if (sz > 0) {
- size_t framing;
- void *q;
+ /* Pull out the offset table for the fields array, if any */
+ if (m->fields_size > 0) {
+ sz = bus_gvariant_determine_word_size(m->fields_size, 0);
+ if (sz > 0) {
+ size_t framing;
+ void *q;
- ri = m->fields_size - sz;
- r = message_peek_fields(m, &ri, 1, sz, &q);
- if (r < 0)
- return r;
+ if (m->fields_size < sz)
+ return -EBADMSG;
- framing = bus_gvariant_read_word_le(q, sz);
- if (framing >= m->fields_size - sz)
- return -EBADMSG;
- if ((m->fields_size - framing) % sz != 0)
- return -EBADMSG;
+ ri = m->fields_size - sz;
+ r = message_peek_fields(m, &ri, 1, sz, &q);
+ if (r < 0)
+ return r;
- ri = framing;
- r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
- if (r < 0)
- return r;
+ framing = bus_gvariant_read_word_le(q, sz);
+ if (framing >= m->fields_size - sz)
+ return -EBADMSG;
+ if ((m->fields_size - framing) % sz != 0)
+ return -EBADMSG;
- n_offsets = (m->fields_size - framing) / sz;
+ ri = framing;
+ r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
+ if (r < 0)
+ return r;
+
+ n_offsets = (m->fields_size - framing) / sz;
+ }
}
} else
m->user_body_size = m->body_size;
if (m->reply_cookie == 0 || !m->error.name)
return -EBADMSG;
break;
+
+ default:
+ assert_not_reached("Bad message type");
}
/* Refuse non-local messages that claim they are local */
static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
assert(p);
+ if (!u || FLAGS_SET(p->flags, SD_BUS_VTABLE_ABSOLUTE_OFFSET))
+ return SIZE_TO_PTR(p->x.method.offset); /* don't add offset on NULL, to make ubsan happy */
+
return (uint8_t*) u + p->x.method.offset;
}
static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
assert(p);
+ if (!u || FLAGS_SET(p->flags, SD_BUS_VTABLE_ABSOLUTE_OFFSET))
+ return SIZE_TO_PTR(p->x.property.offset); /* as above */
+
return (uint8_t*) u + p->x.property.offset;
}
if (r < 0)
return r;
- found_interface = !iface ||
- streq(iface, "org.freedesktop.DBus.Properties") ||
- streq(iface, "org.freedesktop.DBus.Peer") ||
- streq(iface, "org.freedesktop.DBus.Introspectable");
+ found_interface = !iface || STR_IN_SET(iface,
+ "org.freedesktop.DBus.Properties",
+ "org.freedesktop.DBus.Peer",
+ "org.freedesktop.DBus.Introspectable");
LIST_FOREACH(vtables, c, first) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_error *error) {
_cleanup_set_free_free_ Set *s = NULL;
- const char *previous_interface = NULL;
_cleanup_(introspect_free) struct introspect intro = {};
struct node_vtable *c;
bool empty;
if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
continue;
- if (!streq_ptr(previous_interface, c->interface)) {
- if (previous_interface)
- fputs(" </interface>\n", intro.f);
-
- fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
- }
-
- r = introspect_write_interface(&intro, c->vtable);
+ r = introspect_write_interface(&intro, c->interface, c->vtable);
if (r < 0)
return r;
-
- previous_interface = c->interface;
}
- if (previous_interface)
- fputs(" </interface>\n", intro.f);
-
if (empty) {
/* Nothing?, let's see if we exist at all, and if not
* refuse to do anything */
BUS_START_REPLY_SUCCESS = 1,
BUS_START_REPLY_ALREADY_RUNNING = 2,
};
-
-#define BUS_INTROSPECT_DOCTYPE \
- "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
- "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
-
-#define BUS_INTROSPECT_INTERFACE_PEER \
- " <interface name=\"org.freedesktop.DBus.Peer\">\n" \
- " <method name=\"Ping\"/>\n" \
- " <method name=\"GetMachineId\">\n" \
- " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \
- " </method>\n" \
- " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_INTROSPECTABLE \
- " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \
- " <method name=\"Introspect\">\n" \
- " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \
- " </method>\n" \
- " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_PROPERTIES \
- " <interface name=\"org.freedesktop.DBus.Properties\">\n" \
- " <method name=\"Get\">\n" \
- " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
- " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
- " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \
- " </method>\n" \
- " <method name=\"GetAll\">\n" \
- " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
- " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \
- " </method>\n" \
- " <method name=\"Set\">\n" \
- " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \
- " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \
- " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \
- " </method>\n" \
- " <signal name=\"PropertiesChanged\">\n" \
- " <arg type=\"s\" name=\"interface\"/>\n" \
- " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \
- " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \
- " </signal>\n" \
- " </interface>\n"
-
-#define BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER \
- " <interface name=\"org.freedesktop.DBus.ObjectManager\">\n" \
- " <method name=\"GetManagedObjects\">\n" \
- " <arg type=\"a{oa{sa{sv}}}\" name=\"object_paths_interfaces_and_properties\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <signal name=\"InterfacesAdded\">\n" \
- " <arg type=\"o\" name=\"object_path\"/>\n" \
- " <arg type=\"a{sa{sv}}\" name=\"interfaces_and_properties\"/>\n" \
- " </signal>\n" \
- " <signal name=\"InterfacesRemoved\">\n" \
- " <arg type=\"o\" name=\"object_path\"/>\n" \
- " <arg type=\"as\" name=\"interfaces\"/>\n" \
- " </signal>\n" \
- " </interface>\n"
if (b->prefer_writev)
k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
else {
- struct msghdr mh;
- zero(mh);
-
- mh.msg_iov = b->auth_iovec + b->auth_index;
- mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index;
+ struct msghdr mh = {
+ .msg_iov = b->auth_iovec + b->auth_index,
+ .msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index,
+ };
k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
if (k < 0 && errno == ENOTSOCK) {
ssize_t k;
int r;
void *p;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)) control;
bool handle_cmsg = false;
assert(b);
if (b->prefer_readv)
k = readv(b->input_fd, &iov, 1);
else {
- zero(mh);
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- mh.msg_control = &control;
- mh.msg_controllen = sizeof(control);
+ mh = (struct msghdr) {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
- k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (k < 0 && errno == ENOTSOCK) {
+ k = recvmsg_safe(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (k == -ENOTSOCK) {
b->prefer_readv = true;
k = readv(b->input_fd, &iov, 1);
+ if (k < 0)
+ k = -errno;
} else
handle_cmsg = true;
}
+ if (k == -EAGAIN)
+ return 0;
if (k < 0)
- return errno == EAGAIN ? 0 : -errno;
- if (k == 0)
+ return (int) k;
+ if (k == 0) {
+ if (handle_cmsg)
+ cmsg_close_all(&mh); /* paranoia, we shouldn't have gotten any fds on EOF */
return -ECONNRESET;
+ }
b->rbuffer_size += k;
if (m->n_fds > 0 && *idx == 0) {
struct cmsghdr *control;
- mh.msg_control = control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
- mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
+ mh.msg_controllen = CMSG_SPACE(sizeof(int) * m->n_fds);
+ mh.msg_control = alloca0(mh.msg_controllen);
+ control = CMSG_FIRSTHDR(&mh);
+ control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
control->cmsg_level = SOL_SOCKET;
control->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds);
size_t need;
int r;
void *b;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)) control;
bool handle_cmsg = false;
assert(bus);
if (bus->prefer_readv)
k = readv(bus->input_fd, &iov, 1);
else {
- zero(mh);
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
- mh.msg_control = &control;
- mh.msg_controllen = sizeof(control);
+ mh = (struct msghdr) {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
- k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (k < 0 && errno == ENOTSOCK) {
+ k = recvmsg_safe(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (k == -ENOTSOCK) {
bus->prefer_readv = true;
k = readv(bus->input_fd, &iov, 1);
+ if (k < 0)
+ k = -errno;
} else
handle_cmsg = true;
}
+ if (k == -EAGAIN)
+ return 0;
if (k < 0)
- return errno == EAGAIN ? 0 : -errno;
- if (k == 0)
+ return (int) k;
+ if (k == 0) {
+ if (handle_cmsg)
+ cmsg_close_all(&mh); /* On EOF we shouldn't have gotten an fd, but let's make sure */
return -ECONNRESET;
+ }
bus->rbuffer_size += k;
finish:
if (bus) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *q;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *q = NULL;
r = sd_bus_message_new_method_call(
bus,
finish:
if (bus) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *q;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *q = NULL;
r = sd_bus_message_new_method_call(
bus,
assert_se(introspect_begin(&intro, false) >= 0);
- fprintf(intro.f, " <interface name=\"org.foo\">\n");
- assert_se(introspect_write_interface(&intro, vtable) >= 0);
- fputs(" </interface>\n", intro.f);
-
+ assert_se(introspect_write_interface(&intro, "org.foo", vtable) >= 0);
+ /* write again to check if output looks OK for a different interface */
+ assert_se(introspect_write_interface(&intro, "org.foo.bar", vtable) >= 0);
assert_se(introspect_finish(&intro, &s) == 0);
+
fputs(s, stdout);
fputs("\n", stdout);
}
#include <limits.h>
#include <mqueue.h>
#include <netinet/in.h>
+#include <poll.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include "process-util.h"
#include "socket-util.h"
#include "strv.h"
+#include "time-util.h"
#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
return r;
}
+_public_ int sd_notify_barrier(int unset_environment, uint64_t timeout) {
+ _cleanup_close_pair_ int pipe_fd[2] = { -1, -1 };
+ struct timespec ts;
+ int r;
+
+ if (pipe2(pipe_fd, O_CLOEXEC) < 0)
+ return -errno;
+
+ r = sd_pid_notify_with_fds(0, unset_environment, "BARRIER=1", &pipe_fd[1], 1);
+ if (r <= 0)
+ return r;
+
+ pipe_fd[1] = safe_close(pipe_fd[1]);
+
+ struct pollfd pfd = {
+ .fd = pipe_fd[0],
+ /* POLLHUP is implicit */
+ .events = 0,
+ };
+ r = ppoll(&pfd, 1, timeout == UINT64_MAX ? NULL : timespec_store(&ts, timeout), NULL);
+ if (r < 0)
+ return -errno;
+ if (r == 0)
+ return -ETIMEDOUT;
+
+ return 1;
+}
+
_public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
}
sd_device_unref(enumerator->devices[i]);
free(enumerator->devices);
- set_free_free(enumerator->match_subsystem);
- set_free_free(enumerator->nomatch_subsystem);
- hashmap_free_free_free(enumerator->match_sysattr);
- hashmap_free_free_free(enumerator->nomatch_sysattr);
- hashmap_free_free_free(enumerator->match_property);
- set_free_free(enumerator->match_sysname);
- set_free_free(enumerator->match_tag);
- set_free_free(enumerator->match_parent);
+ set_free(enumerator->match_subsystem);
+ set_free(enumerator->nomatch_subsystem);
+ hashmap_free(enumerator->match_sysattr);
+ hashmap_free(enumerator->nomatch_sysattr);
+ hashmap_free(enumerator->match_property);
+ set_free(enumerator->match_sysname);
+ set_free(enumerator->match_tag);
+ set_free(enumerator->match_parent);
return mfree(enumerator);
}
else
set = &enumerator->nomatch_subsystem;
- r = set_ensure_allocated(set, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(*set, subsystem);
- if (r < 0)
+ r = set_put_strdup(set, subsystem);
+ if (r <= 0)
return r;
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
-_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
- _cleanup_free_ char *sysattr = NULL, *value = NULL;
+_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match) {
Hashmap **hashmap;
int r;
assert_return(enumerator, -EINVAL);
- assert_return(_sysattr, -EINVAL);
+ assert_return(sysattr, -EINVAL);
if (match)
hashmap = &enumerator->match_sysattr;
else
hashmap = &enumerator->nomatch_sysattr;
- r = hashmap_ensure_allocated(hashmap, NULL);
- if (r < 0)
- return r;
-
- sysattr = strdup(_sysattr);
- if (!sysattr)
- return -ENOMEM;
-
- if (_value) {
- value = strdup(_value);
- if (!value)
- return -ENOMEM;
- }
-
- r = hashmap_put(*hashmap, sysattr, value);
- if (r < 0)
+ r = hashmap_put_strdup(hashmap, sysattr, value);
+ if (r <= 0)
return r;
- sysattr = NULL;
- value = NULL;
-
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
-_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
- _cleanup_free_ char *property = NULL, *value = NULL;
+_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value) {
int r;
assert_return(enumerator, -EINVAL);
- assert_return(_property, -EINVAL);
-
- r = hashmap_ensure_allocated(&enumerator->match_property, NULL);
- if (r < 0)
- return r;
-
- property = strdup(_property);
- if (!property)
- return -ENOMEM;
-
- if (_value) {
- value = strdup(_value);
- if (!value)
- return -ENOMEM;
- }
+ assert_return(property, -EINVAL);
- r = hashmap_put(enumerator->match_property, property, value);
- if (r < 0)
+ r = hashmap_put_strdup(&enumerator->match_property, property, value);
+ if (r <= 0)
return r;
- property = NULL;
- value = NULL;
-
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
assert_return(enumerator, -EINVAL);
assert_return(sysname, -EINVAL);
- r = set_ensure_allocated(&enumerator->match_sysname, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(enumerator->match_sysname, sysname);
- if (r < 0)
+ r = set_put_strdup(&enumerator->match_sysname, sysname);
+ if (r <= 0)
return r;
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
_public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
assert_return(enumerator, -EINVAL);
assert_return(tag, -EINVAL);
- r = set_ensure_allocated(&enumerator->match_tag, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(enumerator->match_tag, tag);
- if (r < 0)
+ r = set_put_strdup(&enumerator->match_tag, tag);
+ if (r <= 0)
return r;
enumerator->scan_uptodate = false;
- return 0;
-}
-
-static void device_enumerator_clear_match_parent(sd_device_enumerator *enumerator) {
- if (!enumerator)
- return;
-
- set_clear_free(enumerator->match_parent);
+ return 1;
}
int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
const char *path;
int r;
- assert_return(enumerator, -EINVAL);
- assert_return(parent, -EINVAL);
+ assert(enumerator);
+ assert(parent);
r = sd_device_get_syspath(parent, &path);
if (r < 0)
return r;
- r = set_ensure_allocated(&enumerator->match_parent, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(enumerator->match_parent, path);
- if (r < 0)
+ r = set_put_strdup(&enumerator->match_parent, path);
+ if (r <= 0)
return r;
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
- device_enumerator_clear_match_parent(enumerator);
+ assert_return(enumerator, -EINVAL);
+ assert_return(parent, -EINVAL);
+
+ set_clear(enumerator->match_parent);
+
return device_enumerator_add_match_parent_incremental(enumerator, parent);
}
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
enumerator->scan_uptodate = false;
- return 0;
+ return 1;
}
static int device_compare(sd_device * const *_a, sd_device * const *_b) {
.iov_base = &buf,
.iov_len = sizeof(buf)
};
- char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
union sockaddr_union snl;
struct msghdr smsg = {
.msg_iov = &iov,
.msg_iovlen = 1,
- .msg_control = cred_msg,
- .msg_controllen = sizeof(cred_msg),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
.msg_name = &snl,
.msg_namelen = sizeof(snl),
};
ordered_hashmap_free_free_free(device->properties);
ordered_hashmap_free_free_free(device->properties_db);
hashmap_free_free_free(device->sysattr_values);
- set_free_free(device->sysattrs);
- set_free_free(device->tags);
- set_free_free(device->devlinks);
+ set_free(device->sysattrs);
+ set_free(device->tags);
+ set_free(device->devlinks);
return mfree(device);
}
if (!is_valid_tag(tag))
return -EINVAL;
- r = set_ensure_allocated(&device->tags, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put_strdup(device->tags, tag);
+ r = set_put_strdup(&device->tags, tag);
if (r < 0)
return r;
assert(device);
assert(devlink);
- r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put_strdup(device->devlinks, devlink);
+ r = set_put_strdup(&device->devlinks, devlink);
if (r < 0)
return r;
if (!dir)
return -errno;
- r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
- if (r < 0)
- return r;
-
FOREACH_DIRENT_ALL(dent, dir, return -errno) {
_cleanup_free_ char *path = NULL;
struct stat statbuf;
if (!(statbuf.st_mode & S_IRUSR))
continue;
- r = set_put_strdup(device->sysattrs, dent->d_name);
+ r = set_put_strdup(&device->sysattrs, dent->d_name);
if (r < 0)
return r;
}
#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
-#define RTNL_WQUEUE_MAX 1024
#define RTNL_RQUEUE_MAX 64*1024
#define RTNL_CONTAINER_DEPTH 32
#include "socket-util.h"
#include "strv.h"
-#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
-#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
+#define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
+ /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
+ assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
if (r < 0) {
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
+ assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
if (r < 0)
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
+ assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
if (r < 0)
int r;
assert_return(m, -EINVAL);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
+ assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL);
r = type_system_get_type(m->containers[m->n_containers].type_system,
&nl_type,
int r;
assert_return(m, -EINVAL);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
+ assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL);
r = netlink_message_read_internal(m, type_id, &container, NULL);
if (r < 0)
#include "socket-util.h"
#include "util.h"
+/* For some reason we need some extra cmsg space on some kernels. It's not clear why, and one of those days
+ * we need to track this down. See: https://github.com/systemd/systemd/pull/15457 */
+#define EXTRA_CMSG_SPACE 1024
+
int socket_open(int family) {
int fd;
return k;
}
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
+static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) {
union sockaddr_union sender;
- uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo)) + EXTRA_CMSG_SPACE) control;
struct msghdr msg = {
.msg_iov = iov,
.msg_iovlen = 1,
.msg_name = &sender,
.msg_namelen = sizeof(sender),
- .msg_control = cmsg_buffer,
- .msg_controllen = sizeof(cmsg_buffer),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
};
- struct cmsghdr *cmsg;
- uint32_t group = 0;
ssize_t n;
assert(fd >= 0);
assert(iov);
- n = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
- if (n < 0) {
- /* no data */
- if (errno == ENOBUFS)
- log_debug("rtnl: kernel receive buffer overrun");
- else if (errno == EAGAIN)
- log_debug("rtnl: no data in socket");
-
- return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
- }
+ n = recvmsg_safe(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
+ if (n == -ENOBUFS)
+ return log_debug_errno(n, "rtnl: kernel receive buffer overrun");
+ if (IN_SET(n, -EAGAIN, -EINTR))
+ return 0;
+ if (n < 0)
+ return (int) n;
if (sender.nl.nl_pid != 0) {
/* not from the kernel, ignore */
if (peek) {
/* drop the message */
- n = recvmsg(fd, &msg, 0);
+ n = recvmsg_safe(fd, &msg, 0);
if (n < 0)
- return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
+ return (int) n;
}
return 0;
}
- CMSG_FOREACH(cmsg, &msg) {
- if (cmsg->cmsg_level == SOL_NETLINK &&
- cmsg->cmsg_type == NETLINK_PKTINFO &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
- struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
+ if (ret_mcast_group) {
+ struct nl_pktinfo *pi;
- /* multi-cast group */
- group = pktinfo->group;
- }
+ pi = CMSG_FIND_DATA(&msg, SOL_NETLINK, NETLINK_PKTINFO, struct nl_pktinfo);
+ if (pi)
+ *ret_mcast_group = pi->group;
+ else
+ *ret_mcast_group = 0;
}
- if (_group)
- *_group = group;
-
return (int) n;
}
}
static void test_route(sd_netlink *rtnl) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
struct in_addr addr, addr_data;
uint32_t index = 2, u32_data;
int r;
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.locale1",
- "/org/freedesktop/locale1",
- "org.freedesktop.locale1",
- "SetLocale");
+ r = bus_message_new_method_call(bus, &m, bus_locale, "SetLocale");
if (r < 0)
return bus_log_create_error(r);
map = argv[1];
toggle_map = argc > 2 ? argv[2] : "";
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.locale1",
- "/org/freedesktop/locale1",
- "org.freedesktop.locale1",
+ bus_locale,
"SetVConsoleKeyboard",
&error,
NULL,
variant = argc > 3 ? argv[3] : "";
options = argc > 4 ? argv[4] : "";
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.locale1",
- "/org/freedesktop/locale1",
- "org.freedesktop.locale1",
+ bus_locale,
"SetX11Keyboard",
&error,
NULL,
#include "missing_capability.h"
#include "path-util.h"
#include "selinux-util.h"
+#include "service-util.h"
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
return -EINVAL;
}
+static int process_locale_list_item(
+ const char *assignment,
+ char *new_locale[static _VARIABLE_LC_MAX],
+ sd_bus_error *error) {
+
+ assert(assignment);
+ assert(new_locale);
+
+ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) {
+ const char *name, *e;
+
+ assert_se(name = locale_variable_to_string(p));
+
+ e = startswith(assignment, name);
+ if (!e)
+ continue;
+
+ if (*e != '=')
+ continue;
+
+ e++;
+
+ if (!locale_is_valid(e))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s is not valid, refusing.", e);
+ if (locale_is_installed(e) <= 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s not installed, refusing.", e);
+ if (new_locale[p])
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name);
+
+ new_locale[p] = strdup(e);
+ if (!new_locale[p])
+ return -ENOMEM;
+
+ return 0;
+ }
+
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment);
+}
+
static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
_cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {};
_cleanup_strv_free_ char **settings = NULL, **l = NULL;
Context *c = userdata;
bool modified = false;
- int interactive, p, r;
+ int interactive, r;
char **i;
assert(m);
assert(c);
- r = bus_message_read_strv_extend(m, &l);
+ r = sd_bus_message_read_strv(m, &l);
if (r < 0)
return r;
return r;
/* If single locale without variable name is provided, then we assume it is LANG=. */
- if (strv_length(l) == 1 && !strchr(*l, '=')) {
- if (!locale_is_valid(*l))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
+ if (strv_length(l) == 1 && !strchr(l[0], '=')) {
+ if (!locale_is_valid(l[0]))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid locale specification: %s", l[0]);
+ if (locale_is_installed(l[0]) <= 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified locale is not installed: %s", l[0]);
- new_locale[VARIABLE_LANG] = strdup(*l);
+ new_locale[VARIABLE_LANG] = strdup(l[0]);
if (!new_locale[VARIABLE_LANG])
return -ENOMEM;
/* Check whether a variable is valid */
STRV_FOREACH(i, l) {
- bool valid = false;
-
- for (p = 0; p < _VARIABLE_LC_MAX; p++) {
- size_t k;
- const char *name;
-
- name = locale_variable_to_string(p);
- assert(name);
-
- k = strlen(name);
- if (startswith(*i, name) &&
- (*i)[k] == '=' &&
- locale_is_valid((*i) + k + 1)) {
- valid = true;
-
- new_locale[p] = strdup((*i) + k + 1);
- if (!new_locale[p])
- return -ENOMEM;
-
- break;
- }
- }
-
- if (!valid)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data.");
+ r = process_locale_list_item(*i, new_locale, error);
+ if (r < 0)
+ return r;
}
/* If LANG was specified, but not LANGUAGE, check if we should
}
/* Merge with the current settings */
- for (p = 0; p < _VARIABLE_LC_MAX; p++)
+ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!isempty(c->locale[p]) && isempty(new_locale[p])) {
new_locale[p] = strdup(c->locale[p]);
if (!new_locale[p])
locale_simplify(new_locale);
- for (p = 0; p < _VARIABLE_LC_MAX; p++)
+ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
if (!streq_ptr(c->locale[p], new_locale[p])) {
modified = true;
break;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- for (p = 0; p < _VARIABLE_LC_MAX; p++)
+ for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++)
free_and_replace(c->locale[p], new_locale[p]);
r = locale_write_data(c, &settings);
SD_BUS_VTABLE_END
};
+static const BusObjectImplementation manager_object = {
+ "/org/freedesktop/locale1",
+ "org.freedesktop.locale1",
+ .vtables = BUS_VTABLES(locale_vtable),
+};
+
static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
if (r < 0)
return log_error_errno(r, "Failed to get system bus connection: %m");
- r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
+ r = bus_add_implementation(bus, &manager_object, c);
if (r < 0)
- return log_error_errno(r, "Failed to register object: %m");
+ return r;
r = bus_log_control_api_register(bus);
if (r < 0)
log_setup_service();
+ r = service_parse_argv("systemd-localed.service",
+ "Manage system locale settings and key mappings.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
+
umask(0022);
mac_selinux_init();
- if (argc != 1)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
-
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = sd_event_default(&event);
int r;
char *ans;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "GetSession",
- error, &reply,
- "s", session_id);
+ r = bus_call_method(bus, bus_login_mgr, "GetSession", error, &reply, "s", session_id);
if (r < 0)
return r;
(void) pager_open(arg_pager_flags);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ListSessions",
- &error, &reply,
- NULL);
+ r = bus_call_method(bus, bus_login_mgr, "ListSessions", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list sessions: %s", bus_error_message(&error, r));
(void) pager_open(arg_pager_flags);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ListUsers",
- &error, &reply,
- NULL);
+ r = bus_call_method(bus, bus_login_mgr, "ListUsers", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list users: %s", bus_error_message(&error, r));
(void) pager_open(arg_pager_flags);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ListSeats",
- &error, &reply,
- NULL);
+ r = bus_call_method(bus, bus_login_mgr, "ListSeats", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list seats: %s", bus_error_message(&error, r));
_cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
const char *path = NULL;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "GetSeat",
- &error, &reply,
- "s", argv[i]);
+ r = bus_call_method(bus, bus_login_mgr, "GetSeat", &error, &reply, "s", argv[i]);
if (r < 0)
return log_error_errno(r, "Failed to get seat: %s", bus_error_message(&error, r));
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
+ bus_login_mgr,
streq(argv[0], "lock-session") ? "LockSession" :
streq(argv[0], "unlock-session") ? "UnlockSession" :
streq(argv[0], "terminate-session") ? "TerminateSession" :
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "KillSession",
- &error, NULL,
- "ssi", argv[i], arg_kill_who, arg_signal);
+ r = bus_call_method(
+ bus,
+ bus_login_mgr,
+ "KillSession",
+ &error, NULL,
+ "ssi", argv[i], arg_kill_who, arg_signal);
if (r < 0)
return log_error_errno(r, "Could not kill session: %s", bus_error_message(&error, -r));
}
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
}
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetUserLinger",
- &error, NULL,
- "ubb", (uint32_t) uid, b, true);
+ r = bus_call_method(
+ bus,
+ bus_login_mgr,
+ "SetUserLinger",
+ &error, NULL,
+ "ubb", (uint32_t) uid, b, true);
if (r < 0)
return log_error_errno(r, "Could not enable linger: %s", bus_error_message(&error, -r));
}
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "TerminateUser",
- &error, NULL,
- "u", (uint32_t) uid);
+ r = bus_call_method(bus, bus_login_mgr, "TerminateUser", &error, NULL, "u", (uint32_t) uid);
if (r < 0)
return log_error_errno(r, "Could not terminate user: %s", bus_error_message(&error, -r));
}
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
+ bus_login_mgr,
"KillUser",
&error, NULL,
"ui", (uint32_t) uid, arg_signal);
for (i = 2; i < argc; i++) {
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
+ bus_login_mgr,
"AttachDevice",
&error, NULL,
"ssb", argv[1], argv[i], true);
-
if (r < 0)
return log_error_errno(r, "Could not attach device: %s", bus_error_message(&error, -r));
}
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "FlushDevices",
- &error, NULL,
- "b", true);
+ r = bus_call_method(bus, bus_login_mgr, "FlushDevices", &error, NULL, "b", true);
if (r < 0)
return log_error_errno(r, "Could not flush devices: %s", bus_error_message(&error, -r));
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
+ bus_login_mgr,
streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
&error, NULL,
NULL);
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "TerminateSeat",
- &error, NULL,
- "s", argv[i]);
+ r = bus_call_method(bus, bus_login_mgr, "TerminateSeat", &error, NULL, "s", argv[i]);
if (r < 0)
return log_error_errno(r, "Could not terminate seat: %s", bus_error_message(&error, -r));
}
continue;
log_device_debug(d, "Found udev node %s for seat %s", node, seat);
- r = set_put_strdup(nodes, node);
+ r = set_put_strdup(&nodes, node);
if (r < 0)
return r;
}
if (r < 0)
goto fail;
- session->type = t;
+ session->original_type = session->type = t;
session->class = c;
session->remote = remote;
session->vtnr = vtnr;
if (w == INHIBIT_SHUTDOWN)
bus_manager_log_shutdown(m, unit_name);
- r = sd_bus_call_method(
+ r = bus_call_method(
m->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"StartUnit",
error,
&reply,
void *userdata,
sd_bus_error *error) {
- Manager *m = userdata;
+ _unused_ Manager *m = userdata;
int r;
assert(message);
void *userdata,
sd_bus_error *error) {
- Manager *m = userdata;
+ _unused_ Manager *m = userdata;
int r;
assert(message);
void *userdata,
sd_bus_error *error) {
- Manager *m = userdata;
+ _unused_ Manager *m = userdata;
int r;
assert(message);
void *userdata,
sd_bus_error *error) {
- Manager *m = userdata;
+ _unused_ Manager *m = userdata;
int r;
assert(message);
return r;
}
-const sd_bus_vtable manager_vtable[] = {
+static const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
SD_BUS_VTABLE_END
};
+const BusObjectImplementation manager_object = {
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ .vtables = BUS_VTABLES(manager_vtable),
+ .children = BUS_IMPLEMENTATIONS(&seat_object,
+ &session_object,
+ &user_object),
+};
+
static int session_jobs_reply(Session *s, uint32_t jid, const char *unit, const char *result) {
assert(s);
assert(unit);
assert(pid > 1);
assert(job);
- r = sd_bus_message_new_method_call(
- manager->bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(manager->bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return r;
assert(unit);
assert(job);
- r = sd_bus_call_method(
+ r = bus_call_method(
manager->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"StartUnit",
error,
&reply,
assert(unit);
assert(job);
- r = sd_bus_call_method(
+ r = bus_call_method(
manager->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"StopUnit",
error,
&reply,
assert(manager);
assert(unit);
- return sd_bus_call_method(
+ return bus_call_method(
manager->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"KillUnit",
error,
NULL,
#include "sd-bus.h"
+#include "bus-util.h"
#include "logind.h"
#include "logind-session.h"
#include "logind-user.h"
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error);
int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *error);
int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *error);
+
+extern const BusObjectImplementation manager_object;
return sd_bus_reply_method_return(message, NULL);
}
-const sd_bus_vtable seat_vtable[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("CanMultiSession", "b", property_get_const_true, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
- SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-
- SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_METHOD_WITH_NAMES("ActivateSession",
- "s",
- SD_BUS_PARAM(session_id),
- NULL,,
- method_activate_session,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SwitchTo",
- "u",
- SD_BUS_PARAM(vtnr),
- NULL,,
- method_switch_to,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_VTABLE_END
-};
-
-int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *e = NULL;
sd_bus_message *message;
Manager *m = userdata;
return strjoin("/org/freedesktop/login1/seat/", t);
}
-int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
sd_bus_message *message;
Manager *m = userdata;
return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
}
+
+static const sd_bus_vtable seat_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+
+ SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("CanMultiSession", "b", property_get_const_true, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
+ SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+
+ SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+
+ SD_BUS_METHOD_WITH_NAMES("ActivateSession",
+ "s",
+ SD_BUS_PARAM(session_id),
+ NULL,,
+ method_activate_session,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SwitchTo",
+ "u",
+ SD_BUS_PARAM(vtnr),
+ NULL,,
+ method_switch_to,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
+
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation seat_object = {
+ "/org/freedesktop/login1/seat",
+ "org.freedesktop.login1.Seat",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({seat_vtable, seat_object_find}),
+ .node_enumerator = seat_node_enumerator,
+};
#include "sd-bus.h"
#include "logind-seat.h"
+#include "bus-util.h"
-extern const sd_bus_vtable seat_vtable[];
+extern const BusObjectImplementation seat_object;
-int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
char *seat_bus_path(Seat *s);
int seat_send_signal(Seat *s, bool new_seat);
return sd_bus_reply_method_return(message, NULL);
}
+static int method_set_type(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Session *s = userdata;
+ const char *t;
+ SessionType type;
+ int r;
+
+ assert(message);
+ assert(s);
+
+ r = sd_bus_message_read(message, "s", &t);
+ if (r < 0)
+ return r;
+
+ type = session_type_from_string(t);
+ if (type < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Invalid session type '%s'", t);
+
+ if (!session_is_controller(s, sd_bus_message_get_sender(message)))
+ return sd_bus_error_setf(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set type");
+
+ session_set_type(s, type);
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
uint32_t major, minor;
return 1;
}
-const sd_bus_vtable session_vtable[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
-
- SD_BUS_METHOD("Terminate",
- NULL,
- NULL,
- bus_session_method_terminate,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Activate",
- NULL,
- NULL,
- bus_session_method_activate,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Lock",
- NULL,
- NULL,
- bus_session_method_lock,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Unlock",
- NULL,
- NULL,
- bus_session_method_lock,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetIdleHint",
- "b",
- SD_BUS_PARAM(idle),
- NULL,,
- method_set_idle_hint,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLockedHint",
- "b",
- SD_BUS_PARAM(locked),
- NULL,,
- method_set_locked_hint,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("Kill",
- "si",
- SD_BUS_PARAM(who)
- SD_BUS_PARAM(signal_number),
- NULL,,
- bus_session_method_kill,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("TakeControl",
- "b",
- SD_BUS_PARAM(force),
- NULL,,
- method_take_control,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReleaseControl",
- NULL,
- NULL,
- method_release_control,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("TakeDevice",
- "uu",
- SD_BUS_PARAM(major)
- SD_BUS_PARAM(minor),
- "hb",
- SD_BUS_PARAM(fd)
- SD_BUS_PARAM(inactive),
- method_take_device,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("ReleaseDevice",
- "uu",
- SD_BUS_PARAM(major)
- SD_BUS_PARAM(minor),
- NULL,,
- method_release_device,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("PauseDeviceComplete",
- "uu",
- SD_BUS_PARAM(major)
- SD_BUS_PARAM(minor),
- NULL,,
- method_pause_device_complete,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetBrightness",
- "ssu",
- SD_BUS_PARAM(subsystem)
- SD_BUS_PARAM(name)
- SD_BUS_PARAM(brightness),
- NULL,,
- method_set_brightness,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_SIGNAL_WITH_NAMES("PauseDevice",
- "uus",
- SD_BUS_PARAM(major)
- SD_BUS_PARAM(minor)
- SD_BUS_PARAM(type),
- 0),
- SD_BUS_SIGNAL_WITH_NAMES("ResumeDevice",
- "uuh",
- SD_BUS_PARAM(major)
- SD_BUS_PARAM(minor)
- SD_BUS_PARAM(fd),
- 0),
- SD_BUS_SIGNAL("Lock", NULL, 0),
- SD_BUS_SIGNAL("Unlock", NULL, 0),
-
- SD_BUS_VTABLE_END
-};
-
-int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *e = NULL;
sd_bus_message *message;
Manager *m = userdata;
return strjoin("/org/freedesktop/login1/session/", t);
}
-int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
sd_bus_message *message;
Manager *m = userdata;
(uint32_t) s->vtnr,
false);
}
+
+static const sd_bus_vtable session_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+
+ SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Session, id), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("User", "(uo)", property_get_user, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Session, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("VTNr", "u", NULL, offsetof(Session, vtnr), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Seat", "(so)", property_get_seat, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TTY", "s", NULL, offsetof(Session, tty), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Display", "s", NULL, offsetof(Session, display), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Leader", "u", bus_property_get_pid, offsetof(Session, leader), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Audit", "u", NULL, offsetof(Session, audit_id), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Session, type), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Session, class), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Active", "b", property_get_active, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("State", "s", property_get_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+
+ SD_BUS_METHOD("Terminate",
+ NULL,
+ NULL,
+ bus_session_method_terminate,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Activate",
+ NULL,
+ NULL,
+ bus_session_method_activate,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Lock",
+ NULL,
+ NULL,
+ bus_session_method_lock,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Unlock",
+ NULL,
+ NULL,
+ bus_session_method_lock,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SetIdleHint",
+ "b",
+ SD_BUS_PARAM(idle),
+ NULL,,
+ method_set_idle_hint,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SetLockedHint",
+ "b",
+ SD_BUS_PARAM(locked),
+ NULL,,
+ method_set_locked_hint,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("Kill",
+ "si",
+ SD_BUS_PARAM(who)
+ SD_BUS_PARAM(signal_number),
+ NULL,,
+ bus_session_method_kill,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("TakeControl",
+ "b",
+ SD_BUS_PARAM(force),
+ NULL,,
+ method_take_control,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ReleaseControl",
+ NULL,
+ NULL,
+ method_release_control,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SetType",
+ "s",
+ SD_BUS_PARAM(type),
+ NULL,,
+ method_set_type,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("TakeDevice",
+ "uu",
+ SD_BUS_PARAM(major)
+ SD_BUS_PARAM(minor),
+ "hb",
+ SD_BUS_PARAM(fd)
+ SD_BUS_PARAM(inactive),
+ method_take_device,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("ReleaseDevice",
+ "uu",
+ SD_BUS_PARAM(major)
+ SD_BUS_PARAM(minor),
+ NULL,,
+ method_release_device,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("PauseDeviceComplete",
+ "uu",
+ SD_BUS_PARAM(major)
+ SD_BUS_PARAM(minor),
+ NULL,,
+ method_pause_device_complete,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SetBrightness",
+ "ssu",
+ SD_BUS_PARAM(subsystem)
+ SD_BUS_PARAM(name)
+ SD_BUS_PARAM(brightness),
+ NULL,,
+ method_set_brightness,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ SD_BUS_SIGNAL_WITH_NAMES("PauseDevice",
+ "uus",
+ SD_BUS_PARAM(major)
+ SD_BUS_PARAM(minor)
+ SD_BUS_PARAM(type),
+ 0),
+ SD_BUS_SIGNAL_WITH_NAMES("ResumeDevice",
+ "uuh",
+ SD_BUS_PARAM(major)
+ SD_BUS_PARAM(minor)
+ SD_BUS_PARAM(fd),
+ 0),
+ SD_BUS_SIGNAL("Lock", NULL, 0),
+ SD_BUS_SIGNAL("Unlock", NULL, 0),
+
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation session_object = {
+ "/org/freedesktop/login1/session",
+ "org.freedesktop.login1.Session",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({session_vtable, session_object_find}),
+ .node_enumerator = session_node_enumerator,
+};
#include "logind-session.h"
-extern const sd_bus_vtable session_vtable[];
-int session_node_enumerator(sd_bus *bus, const char *path,void *userdata, char ***nodes, sd_bus_error *error);
-int session_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
+extern const BusObjectImplementation session_object;
+
char *session_bus_path(Session *s);
int session_send_signal(Session *s, bool new_session);
if (s->type >= 0)
fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
+ if (s->original_type >= 0)
+ fprintf(f, "ORIGINAL_TYPE=%s\n", session_type_to_string(s->original_type));
+
if (s->class >= 0)
fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
*position = NULL,
*leader = NULL,
*type = NULL,
+ *original_type = NULL,
*class = NULL,
*uid = NULL,
*realtime = NULL,
"POSITION", &position,
"LEADER", &leader,
"TYPE", &type,
+ "ORIGINAL_TYPE", &original_type,
"CLASS", &class,
"UID", &uid,
"REALTIME", &realtime,
s->type = t;
}
+ if (original_type) {
+ SessionType ot;
+
+ ot = session_type_from_string(original_type);
+ if (ot >= 0)
+ s->original_type = ot;
+ } else
+ /* Pre-v246 compat: initialize original_type if not set in the state file */
+ s->original_type = s->type;
+
if (class) {
SessionClass c;
session_send_changed(s, "LockedHint", NULL);
}
+void session_set_type(Session *s, SessionType t) {
+ assert(s);
+
+ if (s->type == t)
+ return;
+
+ s->type = t;
+ session_save(s);
+
+ session_send_changed(s, "Type", NULL);
+}
+
static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
Session *s = userdata;
return;
s->track = sd_bus_track_unref(s->track);
+ session_set_type(s, s->original_type);
session_release_controller(s, false);
session_save(s);
session_restore_vt(s);
const char *id;
unsigned position;
SessionType type;
+ SessionType original_type;
SessionClass class;
char *state_file;
int session_set_idle_hint(Session *s, bool b);
int session_get_locked_hint(Session *s);
void session_set_locked_hint(Session *s, bool b);
+void session_set_type(Session *s, SessionType t);
int session_create_fifo(Session *s);
int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error);
int session_stop(Session *s, bool force);
return sd_bus_reply_method_return(message, NULL);
}
-const sd_bus_vtable user_vtable[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_PROPERTY("UID", "u", property_get_uid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("GID", "u", property_get_gid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
- SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
-
- SD_BUS_METHOD("Terminate", NULL, NULL, bus_user_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("Kill",
- "i",
- SD_BUS_PARAM(signal_number),
- NULL,,
- bus_user_method_kill,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_VTABLE_END
-};
-
-int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
Manager *m = userdata;
uid_t uid;
User *user;
return s;
}
-int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
sd_bus_message *message;
Manager *m = userdata;
return 1;
}
+static const sd_bus_vtable user_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+
+ SD_BUS_PROPERTY("UID", "u", property_get_uid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("GID", "u", property_get_gid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Name", "s", property_get_name, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(User, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimePath", "s", NULL, offsetof(User, runtime_path), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Service", "s", NULL, offsetof(User, service), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
+ SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
+
+ SD_BUS_METHOD("Terminate", NULL, NULL, bus_user_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("Kill",
+ "i",
+ SD_BUS_PARAM(signal_number),
+ NULL,,
+ bus_user_method_kill,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation user_object = {
+ "/org/freedesktop/login1/user",
+ "org.freedesktop.login1.User",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({user_vtable, user_object_find}),
+ .node_enumerator = user_node_enumerator,
+};
+
int user_send_signal(User *u, bool new_user) {
_cleanup_free_ char *p = NULL;
#include "logind-user.h"
-extern const sd_bus_vtable user_vtable[];
-int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-int user_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
+extern const BusObjectImplementation user_object;
+
char *user_bus_path(User *s);
int user_send_signal(User *u, bool new_user);
#include "bus-error.h"
#include "bus-log-control-api.h"
#include "bus-polkit.h"
+#include "bus-util.h"
#include "cgroup-util.h"
#include "def.h"
#include "device-util.h"
#include "parse-util.h"
#include "process-util.h"
#include "selinux-util.h"
+#include "service-util.h"
#include "signal-util.h"
#include "strv.h"
#include "terminal-util.h"
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
- r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
+ r = bus_add_implementation(m->bus, &manager_object, m);
if (r < 0)
- return log_error_errno(r, "Failed to add manager object vtable: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add seat object vtable: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add seat enumerator: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add session object vtable: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add session enumerator: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add user object vtable: %m");
+ return r;
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
+ r = bus_log_control_api_register(m->bus);
if (r < 0)
- return log_error_errno(r, "Failed to add user enumerator: %m");
+ return r;
- r = sd_bus_match_signal_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "JobRemoved",
- match_job_removed, NULL, m);
+ r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "JobRemoved", match_job_removed, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to request match for JobRemoved: %m");
- r = sd_bus_match_signal_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "UnitRemoved",
- match_unit_removed, NULL, m);
+ r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "UnitRemoved", match_unit_removed, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
if (r < 0)
return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
- r = sd_bus_match_signal_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Reloading",
- match_reloading, NULL, m);
+ r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "Reloading", match_reloading, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to request match for Reloading: %m");
- r = sd_bus_call_method_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Subscribe",
- NULL, NULL,
- NULL);
+ r = bus_call_method_async(m->bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to enable subscription: %m");
- r = bus_log_control_api_register(m->bus);
- if (r < 0)
- return r;
-
r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.login1", 0, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
log_set_facility(LOG_AUTH);
log_setup_service();
- umask(0022);
+ r = service_parse_argv("systemd-logind.service",
+ "Manager for user logins and devices and privileged operations.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
- if (argc != 1) {
- log_error("This program takes no arguments.");
- return -EINVAL;
- }
+ umask(0022);
r = mac_selinux_init();
if (r < 0)
void manager_connect_utmp(Manager *m);
void manager_reconnect_utmp(Manager *m);
-extern const sd_bus_vtable manager_vtable[];
-
/* gperf lookup function */
const struct ConfigPerfItem* logind_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
send_interface="org.freedesktop.login1.Session"
send_member="ReleaseControl"/>
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Session"
+ send_member="SetType"/>
+
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"
send_member="TakeDevice"/>
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
const char *username = NULL, *json = NULL;
+ _cleanup_free_ char *field = NULL;
int r;
assert(handle);
return PAM_SERVICE_ERR;
}
- /* If pam_systemd_homed (or some other module) already acqired the user record we can reuse it
+ /* If pam_systemd_homed (or some other module) already acquired the user record we can reuse it
* here. */
- r = pam_get_data(handle, "systemd-user-record", (const void**) &json);
- if (r != PAM_SUCCESS || !json) {
- _cleanup_free_ char *formatted = NULL;
-
- if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
- pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
- return r;
- }
-
- /* Request the record ourselves */
- r = userdb_by_name(username, 0, &ur);
- if (r < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to get user record: %s", strerror_safe(r));
- return PAM_USER_UNKNOWN;
- }
-
- r = json_variant_format(ur->json, 0, &formatted);
- if (r < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to format user JSON: %s", strerror_safe(r));
- return PAM_SERVICE_ERR;
- }
-
- /* And cache it for everyone else */
- r = pam_set_data(handle, "systemd-user-record", formatted, pam_cleanup_free);
- if (r < 0) {
- pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data: %s", pam_strerror(handle, r));
- return r;
- }
+ field = strjoin("systemd-user-record-", username);
+ if (!field)
+ return pam_log_oom(handle);
- TAKE_PTR(formatted);
- } else {
+ r = pam_get_data(handle, field, (const void**) &json);
+ if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA)) {
+ pam_syslog(handle, LOG_ERR, "Failed to get PAM user record data: %s", pam_strerror(handle, r));
+ return r;
+ }
+ if (r == PAM_SUCCESS && json) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
/* Parse cached record */
pam_syslog(handle, LOG_ERR, "Acquired user record does not match user name.");
return PAM_SERVICE_ERR;
}
+ } else {
+ _cleanup_free_ char *formatted = NULL;
+
+ /* Request the record ourselves */
+ r = userdb_by_name(username, 0, &ur);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to get user record: %s", strerror_safe(r));
+ return PAM_USER_UNKNOWN;
+ }
+
+ r = json_variant_format(ur->json, 0, &formatted);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to format user JSON: %s", strerror_safe(r));
+ return PAM_SERVICE_ERR;
+ }
+
+ /* And cache it for everyone else */
+ r = pam_set_data(handle, field, formatted, pam_cleanup_free);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to set PAM user record data '%s': %s",
+ field, pam_strerror(handle, r));
+ return r;
+ }
+
+ TAKE_PTR(formatted);
}
if (!uid_is_valid(ur->uid)) {
static int export_legacy_dbus_address(
pam_handle_t *handle,
- uid_t uid,
const char *runtime) {
const char *s;
if (pam_getenv(handle, "LANG")) {
if (debug)
pam_syslog(handle, LOG_DEBUG, "PAM environment variable $LANG already set, not changing based on user record.");
- } else if (!locale_is_valid(ur->preferred_language)) {
+ } else if (locale_is_installed(ur->preferred_language) <= 0) {
if (debug)
- pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid locally, not setting $LANG.");
+ pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid or not installed, not setting $LANG.");
} else {
_cleanup_free_ char *joined = NULL;
assert(handle);
- /* Make this a NOP on non-logind systems */
- if (!logind_running())
- return PAM_SUCCESS;
-
if (parse_argv(handle,
argc, argv,
&class_pam,
if (r != PAM_SUCCESS)
return r;
+ /* Make most of this a NOP on non-logind systems */
+ if (!logind_running())
+ goto success;
+
/* Make sure we don't enter a loop by talking to
* systemd-logind when it is actually waiting for the
* background to finish start-up. If the service is
}
}
- r = export_legacy_dbus_address(handle, ur->uid, rt);
+ r = export_legacy_dbus_address(handle, rt);
if (r != PAM_SUCCESS)
return r;
- r = apply_user_record_settings(handle, ur, debug);
- if (r != PAM_SUCCESS)
- return r;
-
- return PAM_SUCCESS;
+ goto success;
}
/* Otherwise, we ask logind to create a session for us */
strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight), strna(runtime_max_sec));
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CreateSession");
+ r = bus_message_new_method_call(bus, &m, bus_login_mgr, "CreateSession");
if (r < 0)
return pam_bus_log_create_error(handle, r);
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
if (debug)
pam_syslog(handle, LOG_DEBUG, "Not creating session: %s", bus_error_message(&error, r));
- return PAM_SUCCESS;
+
+ /* We are already in a session, don't do anything */
+ goto success;
} else {
pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r));
return PAM_SESSION_ERR;
return r;
}
- r = export_legacy_dbus_address(handle, ur->uid, runtime_path);
+ r = export_legacy_dbus_address(handle, runtime_path);
if (r != PAM_SUCCESS)
return r;
}
}
}
+success:
r = apply_user_record_settings(handle, ur, debug);
if (r != PAM_SUCCESS)
return r;
int argc, const char **argv) {
const void *existing = NULL;
+ bool debug = false;
const char *id;
int r;
assert(handle);
+ if (parse_argv(handle,
+ argc, argv,
+ NULL,
+ NULL,
+ NULL,
+ &debug) < 0)
+ return PAM_SESSION_ERR;
+
+ if (debug)
+ pam_syslog(handle, LOG_DEBUG, "pam-systemd shutting down");
+
/* Only release session if it wasn't pre-existing when we
* tried to create it */
(void) pam_get_data(handle, "systemd.existing", &existing);
if (r != PAM_SUCCESS)
return r;
- r = sd_bus_call_method(bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ReleaseSession",
- &error,
- NULL,
- "s",
- id);
+ r = bus_call_method(bus, bus_login_mgr, "ReleaseSession", &error, NULL, "s", id);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to release session: %s", bus_error_message(&error, r));
return PAM_SESSION_ERR;
#
# Used by systemd --user instances.
-account required pam_unix.so
+m4_ifdef(`ENABLE_HOMED',
+-account sufficient pam_systemd_home.so
+)m4_dnl
+account sufficient pam_unix.so
+account required pam_permit.so
+
m4_ifdef(`HAVE_SELINUX',
session required pam_selinux.so close
session required pam_selinux.so nottys open
)m4_dnl
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
+m4_ifdef(`ENABLE_HOMED',
+-session optional pam_systemd_home.so
+)m4_dnl
session optional pam_systemd.so
return bus_reply_pair_array(message, image->os_release);
}
-const sd_bus_vtable image_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
- SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
- SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
- SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
- SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
- SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
- SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
- SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
- SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
- SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_VTABLE_END
-};
-
static int image_flush_cache(sd_event_source *s, void *userdata) {
Manager *m = userdata;
return 0;
}
-int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *e = NULL;
Manager *m = userdata;
Image *image = NULL;
return strjoin("/org/freedesktop/machine1/image/", e);
}
-int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_hashmap_free_ Hashmap *images = NULL;
_cleanup_strv_free_ char **l = NULL;
Image *image;
return 1;
}
+
+const sd_bus_vtable image_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
+ SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
+ SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
+ SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
+ SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
+ SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
+ SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
+ SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
+ SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
+ SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
+ SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation image_object = {
+ "/org/freedesktop/machine1/image",
+ "org.freedesktop.machine1.Image",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({image_vtable, image_object_find}),
+ .node_enumerator = image_node_enumerator,
+};
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "bus-util.h"
#include "machined.h"
-extern const sd_bus_vtable image_vtable[];
+extern const BusObjectImplementation image_object;
char *image_bus_path(const char *name);
-int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-
int bus_image_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_image_method_rename(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_image_method_clone(sd_bus_message *message, void *userdata, sd_bus_error *error);
getty = strjoina("container-getty@", p, ".service");
- r = sd_bus_call_method(
- container_bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartUnit",
- error, NULL,
- "ss", getty, "replace");
+ r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, NULL, "ss", getty, "replace");
if (r < 0)
return r;
container_bus = allocated_bus ?: m->manager->bus;
- r = sd_bus_message_new_method_call(
- container_bus,
- &tm,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return r;
return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
}
-const sd_bus_vtable machine_vtable[] = {
+static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+ Manager *m = userdata;
+ Machine *machine;
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(interface);
+ assert(found);
+ assert(m);
+
+ if (streq(path, "/org/freedesktop/machine1/machine/self")) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ sd_bus_message *message;
+ pid_t pid;
+
+ message = sd_bus_get_current_message(bus);
+ if (!message)
+ return 0;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_pid(creds, &pid);
+ if (r < 0)
+ return r;
+
+ r = manager_get_machine_by_pid(m, pid, &machine);
+ if (r <= 0)
+ return 0;
+ } else {
+ _cleanup_free_ char *e = NULL;
+ const char *p;
+
+ p = startswith(path, "/org/freedesktop/machine1/machine/");
+ if (!p)
+ return 0;
+
+ e = bus_label_unescape(p);
+ if (!e)
+ return -ENOMEM;
+
+ machine = hashmap_get(m->machines, e);
+ if (!machine)
+ return 0;
+ }
+
+ *found = machine;
+ return 1;
+}
+
+char *machine_bus_path(Machine *m) {
+ _cleanup_free_ char *e = NULL;
+
+ assert(m);
+
+ e = bus_label_escape(m->name);
+ if (!e)
+ return NULL;
+
+ return strjoin("/org/freedesktop/machine1/machine/", e);
+}
+
+static int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+ _cleanup_strv_free_ char **l = NULL;
+ Machine *machine = NULL;
+ Manager *m = userdata;
+ Iterator i;
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(nodes);
+
+ HASHMAP_FOREACH(machine, m->machines, i) {
+ char *p;
+
+ p = machine_bus_path(machine);
+ if (!p)
+ return -ENOMEM;
+
+ r = strv_consume(&l, p);
+ if (r < 0)
+ return r;
+ }
+
+ *nodes = TAKE_PTR(l);
+
+ return 1;
+}
+
+static const sd_bus_vtable machine_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
-int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- Machine *machine;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- if (streq(path, "/org/freedesktop/machine1/machine/self")) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- sd_bus_message *message;
- pid_t pid;
-
- message = sd_bus_get_current_message(bus);
- if (!message)
- return 0;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- r = manager_get_machine_by_pid(m, pid, &machine);
- if (r <= 0)
- return 0;
- } else {
- _cleanup_free_ char *e = NULL;
- const char *p;
-
- p = startswith(path, "/org/freedesktop/machine1/machine/");
- if (!p)
- return 0;
-
- e = bus_label_unescape(p);
- if (!e)
- return -ENOMEM;
-
- machine = hashmap_get(m->machines, e);
- if (!machine)
- return 0;
- }
-
- *found = machine;
- return 1;
-}
-
-char *machine_bus_path(Machine *m) {
- _cleanup_free_ char *e = NULL;
-
- assert(m);
-
- e = bus_label_escape(m->name);
- if (!e)
- return NULL;
-
- return strjoin("/org/freedesktop/machine1/machine/", e);
-}
-
-int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
- _cleanup_strv_free_ char **l = NULL;
- Machine *machine = NULL;
- Manager *m = userdata;
- Iterator i;
- int r;
-
- assert(bus);
- assert(path);
- assert(nodes);
-
- HASHMAP_FOREACH(machine, m->machines, i) {
- char *p;
-
- p = machine_bus_path(machine);
- if (!p)
- return -ENOMEM;
-
- r = strv_consume(&l, p);
- if (r < 0)
- return r;
- }
-
- *nodes = TAKE_PTR(l);
-
- return 1;
-}
+const BusObjectImplementation machine_object = {
+ "/org/freedesktop/machine1/machine",
+ "org.freedesktop.machine1.Machine",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({machine_vtable, machine_object_find}),
+ .node_enumerator = machine_node_enumerator,
+};
int machine_send_signal(Machine *m, bool new_machine) {
_cleanup_free_ char *p = NULL;
#include "sd-bus.h"
+#include "bus-util.h"
#include "machine.h"
-extern const sd_bus_vtable machine_vtable[];
+extern const BusObjectImplementation machine_object;
char *machine_bus_path(Machine *s);
-int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
awaited_args++;
query_res = newa0(const char *, awaited_args);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- method,
- &error,
- &reply, "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, method, &error, &reply, "s", name);
if (r < 0)
return log_debug_errno(r, "Failed to call '%s()': %s", method, bus_error_message(&error, r));
assert(prefix);
assert(prefix2);
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetMachineAddresses",
- NULL,
- &reply,
- "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
if (r < 0)
return log_debug_errno(r, "Could not get addresses: %s", bus_error_message(&error, r));
(void) pager_open(arg_pager_flags);
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "ListMachines",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_machine_mgr, "ListMachines", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Could not get machines: %s", bus_error_message(&error, r));
(void) pager_open(arg_pager_flags);
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "ListImages",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_machine_mgr, "ListImages", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Could not get images: %s", bus_error_message(&error, r));
assert(bus);
assert(name);
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetMachineUIDShift",
- &error,
- &reply,
- "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetMachineUIDShift", &error, &reply, "s", name);
if (r < 0)
return log_debug_errno(r, "Failed to query UID/GID shift: %s", bus_error_message(&error, r));
for (int i = 1; i < argc; i++) {
const char *path = NULL;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetMachine",
- &error,
- &reply,
- "s", argv[i]);
+ r = bus_call_method(bus, bus_machine_mgr, "GetMachine", &error, &reply, "s", argv[i]);
if (r < 0)
return log_error_errno(r, "Could not get path to machine: %s", bus_error_message(&error, -r));
const char *hn;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetImageHostname",
- NULL, &reply, "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetImageHostname", NULL, &reply, "s", name);
if (r < 0)
return r;
size_t size;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetImageMachineID",
- NULL, &reply, "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetImageMachineID", NULL, &reply, "s", name);
if (r < 0)
return r;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetImageMachineInfo",
- NULL, &reply, "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetImageMachineInfo", NULL, &reply, "s", name);
if (r < 0)
return r;
for (int i = 1; i < argc; i++) {
const char *path = NULL;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetImage",
- &error,
- &reply,
- "s", argv[i]);
+ r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, &reply, "s", argv[i]);
if (r < 0)
return log_error_errno(r, "Could not get path to image: %s", bus_error_message(&error, -r));
arg_kill_who = "all";
for (int i = 1; i < argc; i++) {
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
+ bus_machine_mgr,
"KillMachine",
&error,
NULL,
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
for (int i = 1; i < argc; i++) {
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "TerminateMachine",
- &error,
- NULL,
- "s", argv[i]);
+ r = bus_call_method(bus, bus_machine_mgr, "TerminateMachine", &error, NULL, "s", argv[i]);
if (r < 0)
return log_error_errno(r, "Could not terminate machine: %s", bus_error_message(&error, -r));
}
host_path = abs_host_path;
}
- r = sd_bus_message_new_method_call(
+ r = bus_message_new_method_call(
bus,
&m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
+ bus_machine_mgr,
copy_from ? "CopyFromMachine" : "CopyToMachine");
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
+ bus_machine_mgr,
"BindMountMachine",
&error,
NULL,
if (r < 0)
return log_error_errno(r, "Failed to request machine removal match: %m");
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "OpenMachineLogin",
- &error,
- &reply,
- "s", machine);
+ r = bus_call_method(bus, bus_machine_mgr, "OpenMachineLogin", &error, &reply, "s", machine);
if (r < 0)
return log_error_errno(r, "Failed to get login PTY: %s", bus_error_message(&error, -r));
if (r < 0)
return log_error_errno(r, "Failed to request machine removal match: %m");
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "OpenMachineShell");
+ r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "OpenMachineShell");
if (r < 0)
return bus_log_create_error(r);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "RemoveImage");
+ r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RemoveImage");
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
+ bus_machine_mgr,
"RenameImage",
&error,
NULL,
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "CloneImage");
+ r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CloneImage");
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "MarkImageReadOnly",
- &error,
- NULL,
- "sb", argv[1], b);
+ r = bus_call_method(bus, bus_machine_mgr, "MarkImageReadOnly", &error, NULL, "sb", argv[1], b);
if (r < 0)
return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, -r));
assert(bus);
assert(name);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetImage",
- &error,
- NULL,
- "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetImage", &error, NULL, "s", name);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_IMAGE))
return 0;
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- r = sd_bus_match_signal_async(
+ r = bus_match_signal_async(
bus,
&slot_job_removed,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
+ bus_import_mgr,
"TransferRemoved",
match_transfer_removed, NULL, &path);
if (r < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ImportTar");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportTar");
if (r < 0)
return bus_log_create_error(r);
return log_error_errno(errno, "Failed to open %s: %m", path);
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ImportRaw");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportRaw");
if (r < 0)
return bus_log_create_error(r);
return log_error_errno(errno, "Failed to open directory '%s': %m", path);
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ImportFileSystem");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportFileSystem");
if (r < 0)
return bus_log_create_error(r);
return log_error_errno(errno, "Failed to open %s: %m", path);
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ExportTar");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportTar");
if (r < 0)
return bus_log_create_error(r);
return log_error_errno(errno, "Failed to open %s: %m", path);
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ExportRaw");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportRaw");
if (r < 0)
return bus_log_create_error(r);
}
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "PullTar");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullTar");
if (r < 0)
return bus_log_create_error(r);
}
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "PullRaw");
+ r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullRaw");
if (r < 0)
return bus_log_create_error(r);
(void) pager_open(arg_pager_flags);
- r = sd_bus_call_method(bus,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ListTransfers",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_import_mgr, "ListTransfers", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Could not get transfers: %s", bus_error_message(&error, -r));
if (r < 0)
return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "CancelTransfer",
- &error,
- NULL,
- "u", id);
+ r = bus_call_method(bus, bus_import_mgr, "CancelTransfer", &error, NULL, "u", id);
if (r < 0)
return log_error_errno(r, "Could not cancel transfer: %s", bus_error_message(&error, -r));
}
if (argc > 2)
/* With two arguments changes the quota limit of the
* specified image */
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "SetImageLimit",
- &error,
- NULL,
- "st", argv[1], limit);
+ r = bus_call_method(bus, bus_machine_mgr, "SetImageLimit", &error, NULL, "st", argv[1], limit);
else
/* With one argument changes the pool quota limit */
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "SetPoolLimit",
- &error,
- NULL,
- "t", limit);
+ r = bus_call_method(bus, bus_machine_mgr, "SetPoolLimit", &error, NULL, "t", limit);
if (r < 0)
return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "CleanPool");
+ r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CleanPool");
if (r < 0)
return bus_log_create_error(r);
static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
- Manager *m = userdata;
+ _unused_ Manager *m = userdata;
const char *name;
int r;
static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_hashmap_free_ Hashmap *images = NULL;
- Manager *m = userdata;
+ _unused_ Manager *m = userdata;
Image *image;
Iterator i;
int r;
SD_BUS_VTABLE_END
};
+const BusObjectImplementation manager_object = {
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ .vtables = BUS_VTABLES(manager_vtable),
+ .children = BUS_IMPLEMENTATIONS( &machine_object,
+ &image_object ),
+};
+
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path, *result, *unit;
Manager *m = userdata;
assert(m);
assert(unit);
- return sd_bus_call_method(
- m->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "UnrefUnit",
- error,
- NULL,
- "s",
- unit);
+ return bus_call_method(m->bus, bus_systemd_mgr, "UnrefUnit", error, NULL, "s", unit);
}
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
assert(manager);
assert(unit);
- r = sd_bus_call_method(
- manager->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StopUnit",
- error,
- &reply,
- "ss", unit, "fail");
+ r = bus_call_method(manager->bus, bus_systemd_mgr, "StopUnit", error, &reply, "ss", unit, "fail");
if (r < 0) {
if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
assert(manager);
assert(unit);
- return sd_bus_call_method(
- manager->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "KillUnit",
- error,
- NULL,
- "ssi", unit, "all", signo);
+ return bus_call_method(manager->bus, bus_systemd_mgr, "KillUnit", error, NULL, "ssi", unit, "all", signo);
}
int manager_unit_is_active(Manager *manager, const char *unit) {
#include "bus-error.h"
#include "bus-log-control-api.h"
#include "bus-polkit.h"
+#include "bus-util.h"
#include "cgroup-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "machined.h"
#include "main-func.h"
#include "process-util.h"
+#include "service-util.h"
#include "signal-util.h"
#include "special.h"
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
- r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
+ r = bus_add_implementation(m->bus, &manager_object, m);
if (r < 0)
- return log_error_errno(r, "Failed to add manager object vtable: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add machine object vtable: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add machine enumerator: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add image object vtable: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add image enumerator: %m");
+ return r;
- r = sd_bus_match_signal_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "JobRemoved",
- match_job_removed, NULL, m);
+ r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "JobRemoved", match_job_removed, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to add match for JobRemoved: %m");
- r = sd_bus_match_signal_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "UnitRemoved",
- match_unit_removed, NULL, m);
+ r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "UnitRemoved", match_unit_removed, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
if (r < 0)
return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
- r = sd_bus_match_signal_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Reloading",
- match_reloading, NULL, m);
+ r = bus_match_signal_async(m->bus, NULL, bus_systemd_mgr, "Reloading", match_reloading, NULL, m);
if (r < 0)
return log_error_errno(r, "Failed to request match for Reloading: %m");
- r = sd_bus_call_method_async(
- m->bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Subscribe",
- NULL, NULL,
- NULL);
+ r = bus_call_method_async(m->bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to enable subscription: %m");
log_set_facility(LOG_AUTH);
log_setup_service();
- umask(0022);
+ r = service_parse_argv("systemd-machined.service",
+ "Manage registrations of local VMs and containers.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
- if (argc != 1) {
- log_error("This program takes no arguments.");
- return -EINVAL;
- }
+ umask(0022);
/* Always create the directories people can create inotify watches in. Note that some applications might check
* for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
int manager_add_machine(Manager *m, const char *name, Machine **_machine);
int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine);
-extern const sd_bus_vtable manager_vtable[];
+extern const BusObjectImplementation manager_object;
int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error);
int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
if (r < 0)
return log_error_errno(r, "Failed to make mount unit name: %m");
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to make mount unit name: %m");
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to make %s unit name from path %s: %m", suffix + 1, where);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StopUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StopUnit");
if (r < 0)
return bus_log_create_error(r);
#include "alloc-util.h"
#include "bond.h"
+#include "bond-util.h"
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "extract-word.h"
#include "netlink-util.h"
#include "networkd-manager.h"
#include "string-table.h"
-#include "string-util.h"
/*
* Number of seconds between instances where the bonding
#define GRATUITOUS_ARP_MAX 255
#define GRATUITOUS_ARP_DEFAULT 1
-static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
- [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
- [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
- [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
- [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
- [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
- [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
- [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
-
-static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
- [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
- [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
- [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
- [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
- [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
bond_xmit_hash_policy,
BondXmitHashPolicy,
- "Failed to parse bond transmit hash policy")
-
-static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
- [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
- [NETDEV_BOND_LACP_RATE_FAST] = "fast",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
-
-static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
- [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
- [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
- [NETDEV_BOND_AD_SELECT_COUNT] = "count",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+ "Failed to parse bond transmit hash policy");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate");
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
-
-static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
- [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
- [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
- [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
-
-static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
- [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
- [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
- [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
- [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
-
-static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
- [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
- [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
-
-static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
- [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
- [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
- [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
#include <netinet/in.h>
#include <linux/if_bonding.h>
-#include "in-addr-util.h"
+#include "bond-util.h"
+#include "macro.h"
#include "netdev.h"
#include "ordered-set.h"
-/*
- * Maximum number of targets supported by the kernel for a single
- * bond netdev.
- */
-#define NETDEV_BOND_ARP_TARGETS_MAX 16
-
-typedef enum BondMode {
- NETDEV_BOND_MODE_BALANCE_RR = BOND_MODE_ROUNDROBIN,
- NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
- NETDEV_BOND_MODE_BALANCE_XOR = BOND_MODE_XOR,
- NETDEV_BOND_MODE_BROADCAST = BOND_MODE_BROADCAST,
- NETDEV_BOND_MODE_802_3AD = BOND_MODE_8023AD,
- NETDEV_BOND_MODE_BALANCE_TLB = BOND_MODE_TLB,
- NETDEV_BOND_MODE_BALANCE_ALB = BOND_MODE_ALB,
- _NETDEV_BOND_MODE_MAX,
- _NETDEV_BOND_MODE_INVALID = -1
-} BondMode;
-
-typedef enum BondXmitHashPolicy {
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER2 = BOND_XMIT_POLICY_LAYER2,
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER34 = BOND_XMIT_POLICY_LAYER34,
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER23 = BOND_XMIT_POLICY_LAYER23,
- NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23 = BOND_XMIT_POLICY_ENCAP23,
- NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34 = BOND_XMIT_POLICY_ENCAP34,
- _NETDEV_BOND_XMIT_HASH_POLICY_MAX,
- _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
-} BondXmitHashPolicy;
-
-typedef enum BondLacpRate {
- NETDEV_BOND_LACP_RATE_SLOW,
- NETDEV_BOND_LACP_RATE_FAST,
- _NETDEV_BOND_LACP_RATE_MAX,
- _NETDEV_BOND_LACP_RATE_INVALID = -1,
-} BondLacpRate;
-
-typedef enum BondAdSelect {
- NETDEV_BOND_AD_SELECT_STABLE,
- NETDEV_BOND_AD_SELECT_BANDWIDTH,
- NETDEV_BOND_AD_SELECT_COUNT,
- _NETDEV_BOND_AD_SELECT_MAX,
- _NETDEV_BOND_AD_SELECT_INVALID = -1,
-} BondAdSelect;
-
-typedef enum BondFailOverMac {
- NETDEV_BOND_FAIL_OVER_MAC_NONE,
- NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
- NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
- _NETDEV_BOND_FAIL_OVER_MAC_MAX,
- _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
-} BondFailOverMac;
-
-typedef enum BondArpValidate {
- NETDEV_BOND_ARP_VALIDATE_NONE,
- NETDEV_BOND_ARP_VALIDATE_ACTIVE,
- NETDEV_BOND_ARP_VALIDATE_BACKUP,
- NETDEV_BOND_ARP_VALIDATE_ALL,
- _NETDEV_BOND_ARP_VALIDATE_MAX,
- _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
-} BondArpValidate;
-
-typedef enum BondArpAllTargets {
- NETDEV_BOND_ARP_ALL_TARGETS_ANY,
- NETDEV_BOND_ARP_ALL_TARGETS_ALL,
- _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
- _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
-} BondArpAllTargets;
-
-typedef enum BondPrimaryReselect {
- NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
- NETDEV_BOND_PRIMARY_RESELECT_BETTER,
- NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
- _NETDEV_BOND_PRIMARY_RESELECT_MAX,
- _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
-} BondPrimaryReselect;
-
typedef struct Bond {
NetDev meta;
int link_set_bond(Link *link);
-const char *bond_mode_to_string(BondMode d) _const_;
-BondMode bond_mode_from_string(const char *d) _pure_;
-
-const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
-BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
-
-const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
-BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
-
-const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
-BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
-
-const char *bond_ad_select_to_string(BondAdSelect d) _const_;
-BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
-
-const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
-BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
-
-const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
-BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
-
-const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
-BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
-
CONFIG_PARSER_PROTOTYPE(config_parse_bond_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_xmit_hash_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_bond_lacp_rate);
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m");
}
+ if (b->vlan_protocol >= 0) {
+ r = sd_netlink_message_append_u16(req, IFLA_BR_VLAN_PROTOCOL, b->vlan_protocol);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_PROTOCOL attribute: %m");
+ }
+
if (b->stp >= 0) {
r = sd_netlink_message_append_u32(req, IFLA_BR_STP_STATE, b->stp);
if (r < 0)
b->mcast_querier = -1;
b->mcast_snooping = -1;
b->vlan_filtering = -1;
+ b->vlan_protocol = -1;
b->stp = -1;
b->default_pvid = VLANID_INVALID;
b->forward_delay = USEC_INFINITY;
int mcast_querier;
int mcast_snooping;
int vlan_filtering;
+ int vlan_protocol;
int stp;
uint16_t priority;
uint16_t group_fwd_mask;
#include "conf-parser.h"
#include "ipvlan.h"
+#include "ipvlan-util.h"
#include "networkd-link.h"
-#include "string-table.h"
+#include "string-util.h"
-static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
- [NETDEV_IPVLAN_MODE_L2] = "L2",
- [NETDEV_IPVLAN_MODE_L3] = "L3",
- [NETDEV_IPVLAN_MODE_L3S] = "L3S",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
-
-static const char* const ipvlan_flags_table[_NETDEV_IPVLAN_FLAGS_MAX] = {
- [NETDEV_IPVLAN_FLAGS_BRIGDE] = "bridge",
- [NETDEV_IPVLAN_FLAGS_PRIVATE] = "private",
- [NETDEV_IPVLAN_FLAGS_VEPA] = "vepa",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(ipvlan_flags, IPVlanFlags);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_flags, ipvlan_flags, IPVlanFlags, "Failed to parse ipvlan flags");
static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
#include <netinet/in.h>
#include <linux/if_link.h>
+#include "ipvlan-util.h"
#include "netdev.h"
-typedef enum IPVlanMode {
- NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
- NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
- NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S,
- _NETDEV_IPVLAN_MODE_MAX,
- _NETDEV_IPVLAN_MODE_INVALID = -1
-} IPVlanMode;
-
-typedef enum IPVlanFlags {
- NETDEV_IPVLAN_FLAGS_BRIGDE,
- NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE,
- NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA,
- _NETDEV_IPVLAN_FLAGS_MAX,
- _NETDEV_IPVLAN_FLAGS_INVALID = -1
-} IPVlanFlags;
-
typedef struct IPVlan {
NetDev meta;
extern const NetDevVTable ipvlan_vtable;
extern const NetDevVTable ipvtap_vtable;
-const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
-IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
-
-const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
-IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;
-
CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_flags);
_cleanup_(macsec_transmit_association_free_or_set_invalidp) TransmitAssociation *a = NULL;
_cleanup_(macsec_receive_association_free_or_set_invalidp) ReceiveAssociation *b = NULL;
- _cleanup_free_ void *p;
+ _cleanup_free_ void *p = NULL;
MACsec *s = userdata;
uint8_t *dest;
size_t l;
#include "conf-parser.h"
#include "macvlan.h"
-#include "string-table.h"
+#include "macvlan-util.h"
-static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
- [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
- [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
- [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
- [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
typedef struct MacVlan MacVlan;
+#include "macvlan-util.h"
#include "netdev.h"
-typedef enum MacVlanMode {
- NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
- NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
- NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
- NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
- _NETDEV_MACVLAN_MODE_MAX,
- _NETDEV_MACVLAN_MODE_INVALID = -1
-} MacVlanMode;
-
struct MacVlan {
NetDev meta;
extern const NetDevVTable macvlan_vtable;
extern const NetDevVTable macvtap_vtable;
-const char *macvlan_mode_to_string(MacVlanMode d) _const_;
-MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
-
CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_mode);
Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering)
+Bridge.VLANProtocol, config_parse_vlanprotocol, 0, offsetof(Bridge, vlan_protocol)
Bridge.STP, config_parse_tristate, 0, offsetof(Bridge, stp)
Bridge.MulticastIGMPVersion, config_parse_uint8, 0, offsetof(Bridge, igmp_version)
VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table) /* deprecated */
#include <net/if.h>
#include <netinet/in.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "bond.h"
return r;
/* skip out early if configuration does not match the environment */
- if (!condition_test_list(netdev_raw->conditions, NULL, NULL, NULL)) {
+ if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL)) {
log_debug("%s: Conditions in the file do not match the system environment, skipping.", filename);
return 0;
}
#include "sd-network.h"
#include "alloc-util.h"
+#include "bond-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
#include "geneve-util.h"
#include "glob-util.h"
#include "hwdb-util.h"
+#include "ipvlan-util.h"
#include "local-addresses.h"
#include "locale-util.h"
#include "logs-show.h"
#include "macro.h"
+#include "macvlan-util.h"
#include "main-func.h"
#include "netlink-util.h"
#include "network-internal.h"
uint16_t dest_port;
+ uint8_t proxy;
+ uint8_t learning;
+ uint8_t inerit;
+ uint8_t rsc;
+ uint8_t l2miss;
+ uint8_t l3miss;
+ uint8_t tos;
+ uint8_t ttl;
} VxLanInfo;
typedef struct LinkInfo {
uint32_t updelay;
uint32_t downdelay;
+ /* macvlan and macvtap info */
+ uint32_t macvlan_mode;
+
+ /* ipvlan info */
+ uint16_t ipvlan_mode;
+ uint16_t ipvlan_flags;
+
/* ethtool info */
int autonegotiation;
uint64_t speed;
(void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
(void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_PROXY, &info->vxlan_info.proxy);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_LEARNING, &info->vxlan_info.learning);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_RSC, &info->vxlan_info.rsc);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L3MISS, &info->vxlan_info.l3miss);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L2MISS, &info->vxlan_info.l2miss);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TOS, &info->vxlan_info.tos);
+ (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TTL, &info->vxlan_info.ttl);
} else if (streq(received_kind, "vlan"))
(void) sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &info->vlan_id);
else if (STR_IN_SET(received_kind, "ipip", "sit")) {
} else if (streq(received_kind, "vti6")) {
(void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_LOCAL, &info->local.in6);
(void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6);
+ } else if (STR_IN_SET(received_kind, "macvlan", "macvtap"))
+ (void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode);
+ else if (streq(received_kind, "ipvlan")) {
+ (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_MODE, &info->ipvlan_mode);
+ (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_FLAGS, &info->ipvlan_flags);
}
strncpy(info->netdev_kind, received_kind, IFNAMSIZ);
TABLE_STRING, bridge_state_to_string(info->port_state));
}
} else if (streq_ptr(info->netdev_kind, "bond")) {
- static const struct {
- const char *mode;
- } mode_table[] = {
- { "balance-rr" },
- { "active-backup" },
- { "balance-xor" },
- { "broadcast" },
- { "802.3ad" },
- { "balance-tlb" },
- { "balance-alb" },
- };
-
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "Mode:",
- TABLE_STRING, mode_table[info->mode],
+ TABLE_STRING, bond_mode_to_string(info->mode),
TABLE_EMPTY,
TABLE_STRING, "Miimon:",
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon),
return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "vxlan")) {
+ char ttl[CONST_MAX(STRLEN("auto") + 1, DECIMAL_STR_MAX(uint8_t))];
+
if (info->vxlan_info.vni > 0) {
r = table_add_many(table,
TABLE_EMPTY,
if (r < 0)
return table_log_add_error(r);
}
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "Learning:",
+ TABLE_BOOLEAN, info->vxlan_info.learning);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "RSC:",
+ TABLE_BOOLEAN, info->vxlan_info.rsc);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "L3MISS:",
+ TABLE_BOOLEAN, info->vxlan_info.l3miss);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "L2MISS:",
+ TABLE_BOOLEAN, info->vxlan_info.l2miss);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ if (info->vxlan_info.tos > 1) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "TOS:",
+ TABLE_UINT8, info->vxlan_info.tos);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ if (info->vxlan_info.ttl > 0)
+ xsprintf(ttl, "%" PRIu8, info->vxlan_info.ttl);
+ else
+ strcpy(ttl, "auto");
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "TTL:",
+ TABLE_STRING, ttl);
+ if (r < 0)
+ return table_log_add_error(r);
} else if (streq_ptr(info->netdev_kind, "vlan") && info->vlan_id > 0) {
r = table_add_many(table,
TABLE_EMPTY,
if (r < 0)
return table_log_add_error(r);
}
+ } else if (STRPTR_IN_SET(info->netdev_kind, "macvlan", "macvtap")) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "Mode:",
+ TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
+ if (r < 0)
+ return table_log_add_error(r);
+ } else if (streq_ptr(info->netdev_kind, "ipvlan")) {
+ _cleanup_free_ char *p = NULL, *s = NULL;
+
+ if (info->ipvlan_flags & IPVLAN_F_PRIVATE)
+ p = strdup("private");
+ else if (info->ipvlan_flags & IPVLAN_F_VEPA)
+ p = strdup("vepa");
+ else
+ p = strdup("bridge");
+ if (!p)
+ log_oom();
+
+ s = strjoin(ipvlan_mode_to_string(info->ipvlan_mode), " (", p, ")");
+ if (!s)
+ return log_oom();
+
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "Mode:",
+ TABLE_STRING, s);
+ if (r < 0)
+ return table_log_add_error(r);
}
if (info->has_wlan_link_info) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "RenewLink",
- &error,
- NULL,
- "i", index);
+ r = bus_call_method(bus, bus_network_mgr, "RenewLink", &error, NULL, "i", index);
if (r < 0)
return log_error_errno(r, "Failed to renew dynamic configuration of interface %s: %s",
name, bus_error_message(&error, r));
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "ForceRenewLink",
- &error,
- NULL,
- "i", index);
+ r = bus_call_method(bus, bus_network_mgr, "ForceRenewLink", &error, NULL, "i", index);
if (r < 0)
return log_error_errno(r, "Failed to force renew dynamic configuration of interface %s: %s",
name, bus_error_message(&error, r));
if (r < 0)
return log_error_errno(r, "Failed to connect system bus: %m");
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "Reload",
- &error, NULL, NULL);
+ r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to reload network settings: %m");
SET_FOREACH(p, indexes, j) {
index = PTR_TO_INT(p);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "ReconfigureLink",
- &error, NULL, "i", index);
+ r = bus_call_method(bus, bus_network_mgr, "ReconfigureLink", &error, NULL, "i", index);
if (r < 0) {
char ifname[IF_NAMESIZE + 1];
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "dhcp-internal.h"
+#include "dhcp6-internal.h"
#include "escape.h"
#include "in-addr-util.h"
#include "networkd-dhcp-common.h"
return 0;
}
-int config_parse_dhcp6_mud_url(
+int config_parse_dhcp_user_class(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char ***l = data;
+ int r;
+
+ assert(l);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *l = strv_free(*l);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+
+ r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to split user classes option, ignoring: %s", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ if (ltype == AF_INET) {
+ if (strlen(w) > UINT8_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s length is not in the range 1-255, ignoring.", w);
+ continue;
+ }
+ } else {
+ if (strlen(w) > UINT16_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s length is not in the range 1-65535, ignoring.", w);
+ continue;
+ }
+ }
+
+ r = strv_push(l, w);
+ if (r < 0)
+ return log_oom();
+
+ w = NULL;
+ }
+
+ return 0;
+}
+
+int config_parse_dhcp_vendor_class(
const char *unit,
const char *filename,
unsigned line,
const char *rvalue,
void *data,
void *userdata) {
+ char ***l = data;
+ int r;
+
+ assert(l);
+ assert(lvalue);
+ assert(rvalue);
+ if (isempty(rvalue)) {
+ *l = strv_free(*l);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+
+ r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to split vendor classes option, ignoring: %s", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ if (strlen(w) > UINT8_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s length is not in the range 1-255, ignoring.", w);
+ continue;
+ }
+
+ r = strv_push(l, w);
+ if (r < 0)
+ return log_oom();
+
+ w = NULL;
+ }
+
+ return 0;
+}
+
+int config_parse_dhcp6_mud_url(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
_cleanup_free_ char *unescaped = NULL;
Network *network = data;
int r;
return 0;
}
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+ if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Failed to parse MUD URL '%s', ignoring: %m", rvalue);
void *data,
void *userdata) {
- _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt = NULL, *old = NULL;
+ _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL;
+ _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL;
_cleanup_free_ char *word = NULL, *q = NULL;
OrderedHashmap **options = data;
union in_addr_union addr;
DHCPOptionDataType type;
- uint8_t u, uint8_data;
- uint16_t uint16_data;
+ uint8_t u8, uint8_data;
+ uint16_t u16, uint16_data;
uint32_t uint32_data;
const void *udata;
const char *p;
return 0;
}
- r = safe_atou8(word, &u);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Invalid DHCP option, ignoring assignment: %s", rvalue);
- return 0;
- }
- if (u < 1 || u >= 255) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
- return 0;
+ if (ltype == AF_INET6) {
+ r = safe_atou16(word, &u16);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Invalid DHCP option, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+ if (u16 < 1 || u16 >= UINT16_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+ } else {
+ r = safe_atou8(word, &u8);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Invalid DHCP option, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+ if (u8 < 1 || u8 >= UINT8_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
+ return 0;
+ }
}
word = mfree(word);
r = safe_atou8(p, &uint8_data);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse DHCPv4 uint8 data, ignoring assignment: %s", p);
+ "Failed to parse DHCP uint8 data, ignoring assignment: %s", p);
return 0;
}
r = safe_atou16(p, &uint16_data);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse DHCPv4 uint16 data, ignoring assignment: %s", p);
+ "Failed to parse DHCP uint16 data, ignoring assignment: %s", p);
return 0;
}
r = safe_atou32(p, &uint32_data);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse DHCPv4 uint32 data, ignoring assignment: %s", p);
+ "Failed to parse DHCP uint32 data, ignoring assignment: %s", p);
return 0;
}
r = in_addr_from_string(AF_INET, p, &addr);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse DHCPv4 ipv4address data, ignoring assignment: %s", p);
+ "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p);
return 0;
}
sz = sizeof(addr.in.s_addr);
break;
}
+ case DHCP_OPTION_DATA_IPV6ADDRESS: {
+ r = in_addr_from_string(AF_INET6, p, &addr);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p);
+ return 0;
+ }
+
+ udata = &addr.in6;
+ sz = sizeof(addr.in6.s6_addr);
+ break;
+ }
case DHCP_OPTION_DATA_STRING:
sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q);
if (sz < 0) {
log_syntax(unit, LOG_ERR, filename, line, sz,
- "Failed to decode DHCPv4 option data, ignoring assignment: %s", p);
+ "Failed to decode DHCP option data, ignoring assignment: %s", p);
}
udata = q;
return -EINVAL;
}
- r = sd_dhcp_option_new(u, udata, sz, &opt);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
- return 0;
+ if (ltype == AF_INET6) {
+ r = sd_dhcp6_option_new(u16, udata, sz, &opt6);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ r = ordered_hashmap_ensure_allocated(options, &dhcp6_option_hash_ops);
+ if (r < 0)
+ return log_oom();
+
+ /* Overwrite existing option */
+ old6 = ordered_hashmap_get(*options, UINT_TO_PTR(u16));
+ r = ordered_hashmap_replace(*options, UINT_TO_PTR(u16), opt6);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+ return 0;
+ }
+ TAKE_PTR(opt6);
+ } else {
+ r = sd_dhcp_option_new(u8, udata, sz, &opt4);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops);
+ if (r < 0)
+ return log_oom();
+
+ /* Overwrite existing option */
+ old4 = ordered_hashmap_get(*options, UINT_TO_PTR(u8));
+ r = ordered_hashmap_replace(*options, UINT_TO_PTR(u8), opt4);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue);
+ return 0;
+ }
+ TAKE_PTR(opt4);
}
+ return 0;
+}
- r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops);
- if (r < 0)
- return log_oom();
+int config_parse_dhcp_request_options(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = data;
+ const char *p;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ if (ltype == AF_INET)
+ network->dhcp_request_options = set_free(network->dhcp_request_options);
+ else
+ network->dhcp6_request_options = set_free(network->dhcp6_request_options);
- /* Overwrite existing option */
- old = ordered_hashmap_remove(*options, UINT_TO_PTR(u));
- r = ordered_hashmap_put(*options, UINT_TO_PTR(u), opt);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
return 0;
}
- TAKE_PTR(opt);
+ for (p = rvalue;;) {
+ _cleanup_free_ char *n = NULL;
+ uint32_t i;
+
+ r = extract_first_word(&p, &n, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse DHCP request option, ignoring assignment: %s",
+ rvalue);
+ return 0;
+ }
+ if (r == 0)
+ return 0;
+
+ r = safe_atou32(n, &i);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "DHCP request option is invalid, ignoring assignment: %s", n);
+ continue;
+ }
+
+ if (i < 1 || i >= UINT8_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
+ continue;
+ }
+
+ if (ltype == AF_INET)
+ r = set_ensure_allocated(&network->dhcp_request_options, NULL);
+ else
+ r = set_ensure_allocated(&network->dhcp6_request_options, NULL);
+ if (r < 0)
+ return log_oom();
+
+ if (ltype == AF_INET)
+ r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
+ else
+ r = set_put(network->dhcp6_request_options, UINT32_TO_PTR(i));
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
+ }
+
return 0;
}
[DHCP_OPTION_DATA_UINT32] = "uint32",
[DHCP_OPTION_DATA_STRING] = "string",
[DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address",
+ [DHCP_OPTION_DATA_IPV6ADDRESS] = "ipv6address",
};
DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType);
DHCP_OPTION_DATA_UINT32,
DHCP_OPTION_DATA_STRING,
DHCP_OPTION_DATA_IPV4ADDRESS,
+ DHCP_OPTION_DATA_IPV6ADDRESS,
_DHCP_OPTION_DATA_MAX,
_DHCP_OPTION_DATA_INVALID,
} DHCPOptionDataType;
CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
#include "sd-dhcp-server.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "networkd-dhcp-server.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
-#include "strv.h"
+#include "socket-netlink.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
static Address* link_find_dhcp_server_address(Link *link) {
Address *address;
return sd_dhcp_server_set_servers(s, what, addresses, n_addresses);
}
+static int dhcp4_server_parse_dns_server_string_and_warn(Link *l, const char *string, struct in_addr **addresses, size_t *n_allocated, size_t *n_addresses) {
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *server_name = NULL;
+ union in_addr_union address;
+ int family, r, ifindex = 0;
+
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring: %m", word);
+ continue;
+ }
+
+ /* Only look for IPv4 addresses */
+ if (family != AF_INET)
+ continue;
+
+ /* Never propagate obviously borked data */
+ if (in4_addr_is_null(&address.in) || in4_addr_is_localhost(&address.in))
+ continue;
+
+ if (!GREEDY_REALLOC(*addresses, *n_allocated, *n_addresses + 1))
+ return log_oom();
+
+ (*addresses)[(*n_addresses)++] = address.in;
+ }
+
+ return 0;
+}
+
+static int dhcp4_server_set_dns_from_resolve_conf(Link *link) {
+ _cleanup_free_ struct in_addr *addresses = NULL;
+ size_t n_addresses = 0, n_allocated = 0;
+ _cleanup_fclose_ FILE *f = NULL;
+ int n = 0, r;
+
+ f = fopen(PRIVATE_UPLINK_RESOLV_CONF, "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return 0;
+
+ return log_warning_errno(errno, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF ": %m");
+ }
+
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
+ const char *a;
+ char *l;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF ": %m");
+ if (r == 0)
+ break;
+
+ n++;
+
+ l = strstrip(line);
+ if (IN_SET(*l, '#', ';', 0))
+ continue;
+
+ a = first_word(l, "nameserver");
+ if (!a)
+ continue;
+
+ r = dhcp4_server_parse_dns_server_string_and_warn(link, a, &addresses, &n_allocated, &n_addresses);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
+ }
+
+ if (n_addresses <= 0)
+ return 0;
+
+ return sd_dhcp_server_set_dns(link->dhcp_server, addresses, n_addresses);
+}
+
int dhcp4_server_configure(Link *link) {
bool acquired_uplink = false;
sd_dhcp_option *p;
"Not emitting %s on link, couldn't find suitable uplink.",
dhcp_lease_info_to_string(n));
r = 0;
- } else
+ } else if (uplink->network)
r = link_push_uplink_to_dhcp_server(uplink, n, link->dhcp_server);
+ else if (n == SD_DHCP_LEASE_DNS_SERVERS)
+ r = dhcp4_server_set_dns_from_resolve_conf(link);
}
if (r < 0)
log_link_warning_errno(link, r,
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
}
+ if (link->network->dhcp_fallback_lease_lifetime > 0) {
+ r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
+ }
+
if (link->network->dhcp_send_decline) {
r = configure_dhcpv4_duplicate_address_detection(link);
if (r < 0)
return 0;
}
-int config_parse_dhcp_user_class(
+int config_parse_dhcp_ip_service_type(
const char *unit,
const char *filename,
unsigned line,
void *data,
void *userdata) {
- char ***l = data;
- int r;
-
- assert(l);
+ assert(filename);
assert(lvalue);
assert(rvalue);
- if (isempty(rvalue)) {
- *l = strv_free(*l);
- return 0;
- }
-
- for (;;) {
- _cleanup_free_ char *w = NULL;
-
- r = extract_first_word(&rvalue, &w, NULL, 0);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to split user classes option, ignoring: %s", rvalue);
- break;
- }
- if (r == 0)
- break;
-
- if (strlen(w) > 255) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s length is not in the range 1-255, ignoring.", w);
- continue;
- }
-
- r = strv_push(l, w);
- if (r < 0)
- return log_oom();
-
- w = NULL;
- }
+ if (streq(rvalue, "CS4"))
+ *((int *)data) = IPTOS_CLASS_CS4;
+ else if (streq(rvalue, "CS6"))
+ *((int *)data) = IPTOS_CLASS_CS6;
+ else
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
return 0;
}
-int config_parse_dhcp_request_options(
+int config_parse_dhcp_mud_url(
const char *unit,
const char *filename,
unsigned line,
void *data,
void *userdata) {
+ _cleanup_free_ char *unescaped = NULL;
Network *network = data;
- const char *p;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(data);
if (isempty(rvalue)) {
- network->dhcp_request_options = set_free(network->dhcp_request_options);
+ network->dhcp_mudurl = mfree(network->dhcp_mudurl);
return 0;
}
- for (p = rvalue;;) {
- _cleanup_free_ char *n = NULL;
- uint32_t i;
-
- r = extract_first_word(&p, &n, NULL, 0);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse DHCP request option, ignoring assignment: %s",
- rvalue);
- return 0;
- }
- if (r == 0)
- return 0;
-
- r = safe_atou32(n, &i);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "DHCP request option is invalid, ignoring assignment: %s", n);
- continue;
- }
-
- if (i < 1 || i >= 255) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
- continue;
- }
-
- r = set_ensure_allocated(&network->dhcp_request_options, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
+ r = cunescape(rvalue, 0, &unescaped);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+ return 0;
}
- return 0;
-}
-
-int config_parse_dhcp_ip_service_type(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
+ if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
- if (streq(rvalue, "CS4"))
- *((int *)data) = IPTOS_CLASS_CS4;
- else if (streq(rvalue, "CS6"))
- *((int *)data) = IPTOS_CLASS_CS6;
- else
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
+ return 0;
+ }
- return 0;
+ return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
}
-int config_parse_dhcp_mud_url(
- const char *unit,
+int config_parse_dhcp_fallback_lease_lifetime(const char *unit,
const char *filename,
unsigned line,
const char *section,
const char *rvalue,
void *data,
void *userdata) {
-
- _cleanup_free_ char *unescaped = NULL;
- Network *network = data;
- int r;
+ Network *network = userdata;
+ unsigned k;
assert(filename);
+ assert(section);
assert(lvalue);
assert(rvalue);
+ assert(data);
if (isempty(rvalue)) {
- network->dhcp_mudurl = mfree(network->dhcp_mudurl);
- return 0;
- }
-
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+ network->dhcp_fallback_lease_lifetime = 0;
return 0;
}
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+ /* We accept only "forever" or "infinity". */
+ if (STR_IN_SET(rvalue, "forever", "infinity"))
+ k = CACHE_INFO_INFINITY_LIFE_TIME;
+ else {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
-
+ "Invalid LeaseLifetime= value, ignoring: %s", rvalue);
return 0;
}
- return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
+ network->dhcp_fallback_lease_lifetime = k;
+
+ return 0;
}
static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
+CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_fallback_lease_lifetime);
int dhcp6_configure(Link *link) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
+ sd_dhcp6_option *send_option;
+ void *request_options;
const DUID *duid;
+ Iterator i;
int r;
assert(link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m");
+ ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp6_client_send_options, i) {
+ r = sd_dhcp6_client_add_option(client, send_option);
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set option: %m");
+ }
+
r = dhcp6_set_hostname(client, link);
if (r < 0)
return r;
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set MUD URL: %m");
}
+ SET_FOREACH(request_options, link->network->dhcp6_request_options, i) {
+ uint32_t option = PTR_TO_UINT32(request_options);
+
+ r = sd_dhcp6_client_set_request_option(client, option);
+ if (r == -EEXIST) {
+ log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
+ continue;
+ }
+
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option);
+ }
+
+ if (link->network->dhcp6_user_class) {
+ r = sd_dhcp6_client_set_request_user_class(client, link->network->dhcp6_user_class);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
+ }
+
+ if (link->network->dhcp6_vendor_class) {
+ r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
+ }
+
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
if (r < 0)
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
return -ENOMEM;
STRV_FOREACH(i, ntas) {
- r = set_put_strdup(ns, *i);
+ r = set_put_strdup(&ns, *i);
if (r < 0)
return r;
}
return 0;
}
+static int link_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+ int r;
+
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0)
+ log_link_message_warning_errno(link, m, r, "Could not set group for the interface");
+
+ return 1;
+}
+
+static int link_set_group(Link *link) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+
+ if (link->network->group <= 0)
+ return 0;
+
+ log_link_debug(link, "Setting group");
+
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+
+ r = sd_netlink_message_append_u32(req, IFLA_GROUP, link->network->group);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set link group: %m");
+
+ r = netlink_call_async(link->manager->rtnl, NULL, req, link_group_handler,
+ link_netlink_destroy_callback, link);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
static int link_handle_bound_to_list(Link *link) {
Link *l;
Iterator i;
if (r < 0)
return r;
+ r = link_set_group(link);
+ if (r < 0)
+ return r;
+
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
r = ipv4ll_configure(link);
if (r < 0)
#include "networkd-network.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "tmpfile-util.h"
DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
if (!link->network)
return false;
- /* LLDP should be handled on bridge slaves as those have a direct
- * connection to their peers not on the bridge master. Linux doesn't
- * even (by default) forward lldp packets to the bridge master.*/
- if (streq_ptr("bridge", link->kind))
+ /* LLDP should be handled on bridge and bond slaves as those have a direct connection to their peers,
+ * not on the bridge/bond master. Linux doesn't even (by default) forward lldp packets to the bridge
+ * master.*/
+ if (link->kind && STR_IN_SET(link->kind, "bridge", "bond"))
return false;
return link->network->lldp_mode != LLDP_MODE_NO;
#include <net/if_arp.h>
#include "alloc-util.h"
-#include "escape.h"
#include "env-file.h"
+#include "escape.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "missing_network.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-util.h"
+#include "strv.h"
#include "unaligned.h"
#include "web-util.h"
if (!link->network)
return false;
+ if (link->kind && STR_IN_SET(link->kind, "bridge", "bond"))
+ return false;
+
return link->network->lldp_emit != LLDP_EMIT_NO;
}
}
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- Manager *manager = userdata;
+ _unused_ Manager *manager = userdata;
const sd_bus_error *e;
assert(m);
}
static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- Manager *manager = userdata;
+ _unused_ Manager *manager = userdata;
const sd_bus_error *e;
assert(m);
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, conditions)
Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(Network, mtu)
+Link.Group, config_parse_uint32, 0, offsetof(Network, group)
Link.ARP, config_parse_tristate, 0, offsetof(Network, arp)
Link.Multicast, config_parse_tristate, 0, offsetof(Network, multicast)
Link.AllMulticast, config_parse_tristate, 0, offsetof(Network, allmulticast)
DHCPv4.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
DHCPv4.UseGateway, config_parse_tristate, 0, offsetof(Network, dhcp_use_gateway)
-DHCPv4.RequestOptions, config_parse_dhcp_request_options, 0, 0
+DHCPv4.RequestOptions, config_parse_dhcp_request_options, AF_INET, 0
DHCPv4.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
DHCPv4.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCPv4.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0
DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
-DHCPv4.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
+DHCPv4.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCPv4.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline)
DHCPv4.BlackList, config_parse_dhcp_black_listed_ip_address, 0, 0
DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type, 0, offsetof(Network, ip_service_type)
-DHCPv4.SendOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_options)
+DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu)
+DHCPv4.FallbackLeaseLifetimeSec, config_parse_dhcp_fallback_lease_lifetime, 0, 0
DHCPv6.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp6_use_dns)
DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp)
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
+DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
+DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class)
+DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class)
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
+DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options)
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
-DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
+DHCP.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
#include <net/if.h>
#include <netinet/in.h>
#include <linux/netdevice.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "conf-files.h"
network->filename);
/* skip out early if configuration does not match the environment */
- if (!condition_test_list(network->conditions, NULL, NULL, NULL))
+ if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Conditions in the file do not match the system environment, skipping.",
network->filename);
free(network->dhcp_hostname);
set_free(network->dhcp_black_listed_ip);
set_free(network->dhcp_request_options);
+ set_free(network->dhcp6_request_options);
free(network->mac);
free(network->dhcp6_mudurl);
+ strv_free(network->dhcp6_user_class);
+ strv_free(network->dhcp6_vendor_class);
if (network->dhcp_acd)
sd_ipv4acd_unref(network->dhcp_acd);
uint64_t dhcp_max_attempts;
unsigned dhcp_route_metric;
uint32_t dhcp_route_table;
+ uint32_t dhcp_fallback_lease_lifetime;
uint32_t dhcp_route_mtu;
uint16_t dhcp_client_port;
int dhcp_critical;
bool dhcp6_without_ra;
uint8_t dhcp6_pd_length;
char *dhcp6_mudurl;
+ char **dhcp6_user_class;
+ char **dhcp6_vendor_class;
struct in6_addr dhcp6_pd_address;
+ OrderedHashmap *dhcp6_client_send_options;
+ Set *dhcp6_request_options;
/* DHCP Server Support */
bool dhcp_server;
struct ether_addr *mac;
uint32_t mtu;
+ uint32_t group;
int arp;
int multicast;
int allmulticast;
.type = CONDITION_KERNEL_VERSION,
.parameter = (char *) ">= 4.5"
};
- r = condition_test(&c);
+ r = condition_test(&c, NULL);
if (r < 0)
return r;
test_network_get(manager, loopback);
assert_se(manager_rtnl_enumerate_links(manager) >= 0);
+ return 0;
}
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
+#include "time-util.h"
#include "user-util.h"
#include "util.h"
static bool arg_booted = false;
static uid_t arg_uid = UID_INVALID;
static gid_t arg_gid = GID_INVALID;
+static bool arg_no_block = false;
static int help(void) {
_cleanup_free_ char *link = NULL;
" --uid=USER Set user to send from\n"
" --status=TEXT Set status text\n"
" --booted Check if the system was booted up with systemd\n"
+ " --no-block Do not wait until operation finished\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, ansi_highlight(), ansi_normal()
return 0;
}
+static pid_t manager_pid(void) {
+ const char *e;
+ pid_t pid;
+ int r;
+
+ /* If we run as a service managed by systemd --user the $MANAGERPID environment variable points to
+ * the service manager's PID. */
+ e = getenv("MANAGERPID");
+ if (!e)
+ return 0;
+
+ r = parse_pid(e, &pid);
+ if (r < 0) {
+ log_warning_errno(r, "$MANAGERPID is set to an invalid PID, ignoring: %s", e);
+ return 0;
+ }
+
+ return pid;
+}
+
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_STATUS,
ARG_BOOTED,
ARG_UID,
+ ARG_NO_BLOCK
};
static const struct option options[] = {
{ "status", required_argument, NULL, ARG_STATUS },
{ "booted", no_argument, NULL, ARG_BOOTED },
{ "uid", required_argument, NULL, ARG_UID },
+ { "no-block", no_argument, NULL, ARG_NO_BLOCK },
{}
};
break;
case ARG_PID:
+ if (isempty(optarg) || streq(optarg, "auto")) {
+ arg_pid = getppid();
- if (optarg) {
- if (parse_pid(optarg, &arg_pid) < 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to parse PID %s.", optarg);
- } else
+ if (arg_pid <= 1 ||
+ arg_pid == manager_pid()) /* Don't send from PID 1 or the service
+ * manager's PID (which might be distinct from
+ * 1, if we are a --user instance), that'd just
+ * be confusing for the service manager */
+ arg_pid = getpid();
+ } else if (streq(optarg, "parent"))
arg_pid = getppid();
+ else if (streq(optarg, "self"))
+ arg_pid = getpid();
+ else {
+ r = parse_pid(optarg, &arg_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PID %s.", optarg);
+ }
break;
break;
}
+ case ARG_NO_BLOCK:
+ arg_no_block = true;
+ break;
+
case '?':
return -EINVAL;
_cleanup_strv_free_ char **final_env = NULL;
char* our_env[4];
unsigned i = 0;
+ pid_t source_pid;
int r;
log_show_color(true);
setreuid(arg_uid, (uid_t) -1) < 0)
return log_error_errno(errno, "Failed to change UID: %m");
- r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
+ if (arg_pid > 0)
+ source_pid = arg_pid;
+ else {
+ /* Pretend the message originates from our parent, given that we are typically called from a
+ * shell script, i.e. we are not the main process of a service but only a child of it. */
+ source_pid = getppid();
+ if (source_pid <= 1 ||
+ source_pid == manager_pid()) /* safety check: don't claim we'd send anything from PID 1
+ * or the service manager itself */
+ source_pid = 0;
+ }
+ r = sd_pid_notify(source_pid, false, n);
if (r < 0)
return log_error_errno(r, "Failed to notify init system: %m");
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"No status data could be sent: $NOTIFY_SOCKET was not set");
+
+ if (!arg_no_block) {
+ r = sd_notify_barrier(0, 5 * USEC_PER_SEC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to invoke barrier: %m");
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "No status data could be sent: $NOTIFY_SOCKET was not set");
+ }
+
return 0;
}
* namespace.
*/
static int get_process_controllers(Set **ret) {
- _cleanup_set_free_free_ Set *controllers = NULL;
+ _cleanup_set_free_ Set *controllers = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(ret);
- controllers = set_new(&string_hash_ops);
- if (!controllers)
- return -ENOMEM;
-
f = fopen("/proc/self/cgroup", "re");
if (!f)
return errno == ENOENT ? -ESRCH : -errno;
if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
continue;
- r = set_put_strdup(controllers, l);
+ r = set_put_strdup(&controllers, l);
if (r < 0)
return r;
}
uid_t uid_range,
const char *selinux_apifs_context) {
- _cleanup_set_free_free_ Set *controllers = NULL;
+ _cleanup_set_free_ Set *controllers = NULL;
const char *cgroup_root = "/sys/fs/cgroup", *c;
int r;
* uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
* pass uid 0 and not uid_shift to tmpfs_patch_options().
*/
- r = tmpfs_patch_options("mode=755", 0, selinux_apifs_context, &options);
+ r = tmpfs_patch_options("mode=755" TMPFS_LIMITS_SYS_FS_CGROUP, 0, selinux_apifs_context, &options);
if (r < 0)
return log_oom();
if (r == 0) {
_cleanup_free_ char *options = NULL;
- r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
+ r = tmpfs_patch_options("mode=755" TMPFS_LIMITS_SYS_FS_CGROUP, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
if (r < 0)
return log_oom();
static const MountPoint mount_table[] = {
/* First we list inner child mounts (i.e. mounts applied *after* entering user namespacing) */
{ "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- MOUNT_FATAL|MOUNT_IN_USERNS },
+ MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_MKDIR },
{ "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND,
MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */
PROC_READ_ONLY("/proc/scsi"),
{ "mqueue", "/dev/mqueue", "mqueue", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- MOUNT_IN_USERNS },
+ MOUNT_IN_USERNS|MOUNT_MKDIR },
/* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing) */
- { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP },
- { "tmpfs", "/sys", "tmpfs", "mode=555", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS },
- { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
- MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO }, /* skipped if above was mounted */
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- MOUNT_FATAL }, /* skipped if above was mounted */
- { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME,
- MOUNT_FATAL },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- MOUNT_FATAL },
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- MOUNT_FATAL },
+ { "tmpfs", "/tmp", "tmpfs", "mode=1777" TMPFS_LIMITS_TMP, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP|MOUNT_MKDIR },
+ { "tmpfs", "/sys", "tmpfs", "mode=555" TMPFS_LIMITS_SYS, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS|MOUNT_MKDIR },
+ { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO|MOUNT_MKDIR }, /* skipped if above was mounted */
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_MKDIR }, /* skipped if above was mounted */
+ { "tmpfs", "/dev", "tmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_STRICTATIME,
+ MOUNT_FATAL|MOUNT_MKDIR },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ MOUNT_FATAL|MOUNT_MKDIR },
+ { "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ MOUNT_FATAL|MOUNT_MKDIR },
#if HAVE_SELINUX
- { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
+ { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
0 }, /* Bind mount first */
- { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
0 }, /* Then, make it r/o */
#endif
};
continue;
}
- r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
- if (r < 0 && r != -EEXIST) {
- if (fatal && r != -EROFS)
- return log_error_errno(r, "Failed to create directory %s: %m", where);
+ if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_MKDIR)) {
+ r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
+ if (r < 0 && r != -EEXIST) {
+ if (fatal && r != -EROFS)
+ return log_error_errno(r, "Failed to create directory %s: %m", where);
- log_debug_errno(r, "Failed to create directory %s: %m", where);
- /* If we failed mkdir() or chown() due to the root
- * directory being read only, attempt to mount this fs
- * anyway and let mount_verbose log any errors */
- if (r != -EROFS)
- continue;
+ log_debug_errno(r, "Failed to create directory %s: %m", where);
+
+ /* If we failed mkdir() or chown() due to the root directory being read only,
+ * attempt to mount this fs anyway and let mount_verbose log any errors */
+ if (r != -EROFS)
+ continue;
+ }
}
o = mount_table[k].options;
if (r < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create %s: %m", directory);
- options = "mode=755";
+ options = "mode=755" TMPFS_LIMITS_VOLATILE_STATE;
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
return log_oom();
if (!mkdtemp(template))
return log_error_errno(errno, "Failed to create temporary directory: %m");
- options = "mode=755";
+ options = "mode=755" TMPFS_LIMITS_ROOTFS;
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
goto fail;
if (!mkdtemp(template))
return log_error_errno(errno, "Failed to create temporary directory: %m");
- options = "mode=755";
+ options = "mode=755" TMPFS_LIMITS_ROOTFS;
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
if (r < 0)
goto finish;
MOUNT_APPLY_TMPFS_TMP = 1 << 5, /* if set, /tmp will be mounted as tmpfs */
MOUNT_ROOT_ONLY = 1 << 6, /* if set, only root mounts are mounted */
MOUNT_NON_ROOT_ONLY = 1 << 7, /* if set, only non-root mounts are mounted */
+ MOUNT_MKDIR = 1 << 8, /* if set, make directory to mount over first */
} MountSettingsMask;
typedef enum CustomMountType {
assert(bus);
if (keep_unit) {
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
+ bus_machine_mgr,
"RegisterMachineWithNetwork",
&error,
NULL,
} else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "CreateMachineWithNetwork");
+ r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CreateMachineWithNetwork");
if (r < 0)
return bus_log_create_error(r);
assert(bus);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "UnregisterMachine",
- &error,
- NULL,
- "s",
- machine_name);
+ r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
if (r < 0)
log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
if (r < 0)
return log_error_errno(r, "Failed to mangle scope name: %m");
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to mangle scope name: %m");
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "AbandonScope",
- &error,
- NULL,
- "s",
- scope);
+ r = bus_call_method(bus, bus_systemd_mgr, "AbandonScope", &error, NULL, "s", scope);
if (r < 0) {
log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
sd_bus_error_free(&error);
}
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"KillUnit",
&error,
NULL,
sd_bus_error_free(&error);
}
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "UnrefUnit",
- &error,
- NULL,
- "s",
- scope);
+ r = bus_call_method(bus, bus_systemd_mgr, "UnrefUnit", &error, NULL, "s", scope);
if (r < 0)
log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
if (r < 0)
return r;
+ r = mount_custom(
+ directory,
+ arg_custom_mounts,
+ arg_n_custom_mounts,
+ arg_uid_shift,
+ arg_selinux_apifs_context,
+ MOUNT_NON_ROOT_ONLY);
+ if (r < 0)
+ return r;
+
r = setup_timezone(directory);
if (r < 0)
return r;
if (r < 0)
return r;
- r = mount_custom(
- directory,
- arg_custom_mounts,
- arg_n_custom_mounts,
- arg_uid_shift,
- arg_selinux_apifs_context,
- MOUNT_NON_ROOT_ONLY);
- if (r < 0)
- return r;
-
if (!arg_use_cgns) {
r = mount_cgroups(
directory,
.iov_base = buf,
.iov_len = sizeof(buf)-1,
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)) control;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
- struct cmsghdr *cmsg;
- struct ucred *ucred = NULL;
+ struct ucred *ucred;
ssize_t n;
pid_t inner_child_pid;
_cleanup_strv_free_ char **tags = NULL;
return 0;
}
- n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0;
+ n = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (IN_SET(n, -EAGAIN, -EINTR))
+ return 0;
+ if (n < 0)
+ return log_warning_errno(n, "Couldn't read notification socket: %m");
- return log_warning_errno(errno, "Couldn't read notification socket: %m");
- }
cmsg_close_all(&msghdr);
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
- }
-
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid != inner_child_pid) {
log_debug("Received notify message without valid credentials. Ignoring.");
return 0;
return NSS_STATUS_TRYAGAIN;
}
- /* We respond to our local host name, our hostname suffixed with a single dot. */
+ /* We respond to our local hostname, our hostname suffixed with a single dot. */
if (!streq(name, hn) && !streq_ptr(startswith(name, hn), "."))
goto not_found;
#include "alloc-util.h"
#include "bus-common-errors.h"
+#include "bus-util.h"
#include "env-util.h"
#include "errno-util.h"
#include "format-util.h"
if (r < 0)
goto fail;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetMachineAddresses",
- NULL,
- &reply,
- "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
if (r < 0)
goto fail;
if (r < 0)
goto fail;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetMachineAddresses",
- NULL,
- &reply,
- "s", name);
+ r = bus_call_method(bus, bus_machine_mgr, "GetMachineAddresses", NULL, &reply, "s", name);
if (r < 0)
goto fail;
if (r < 0)
goto fail;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "MapFromMachineUser",
- &error,
- &reply,
- "su",
- machine, (uint32_t) uid);
+ r = bus_call_method(bus, bus_machine_mgr, "MapFromMachineUser", &error, &reply, "su", machine, (uint32_t) uid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "MapToMachineUser",
- &error,
- &reply,
- "u",
- (uint32_t) uid);
+ r = bus_call_method(bus, bus_machine_mgr, "MapToMachineUser", &error, &reply, "u", (uint32_t) uid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING))
return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "MapFromMachineGroup",
- &error,
- &reply,
- "su",
- machine, (uint32_t) gid);
+ r = bus_call_method(bus, bus_machine_mgr, "MapFromMachineGroup", &error, &reply, "su", machine, (uint32_t) gid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
return NSS_STATUS_NOTFOUND;
if (r < 0)
goto fail;
- r = sd_bus_call_method(bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "MapToMachineGroup",
- &error,
- &reply,
- "u",
- (uint32_t) gid);
+ r = bus_call_method(bus, bus_machine_mgr, "MapToMachineGroup", &error, &reply, "u", (uint32_t) gid);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING))
return NSS_STATUS_NOTFOUND;
#include "sd-bus.h"
#include "bus-common-errors.h"
+#include "bus-util.h"
#include "errno-util.h"
#include "in-addr-util.h"
#include "macro.h"
if (r < 0)
goto fail;
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveHostname");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
if (r < 0)
goto fail;
if (r < 0)
goto fail;
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveHostname");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
if (r < 0)
goto fail;
if (r < 0)
goto fail;
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveAddress");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
if (r < 0)
goto fail;
getpwent_data.iterator = userdb_iterator_free(getpwent_data.iterator);
getpwent_data.by_membership = false;
- r = userdb_all(nss_glue_userdb_flags(), &getpwent_data.iterator);
+ /* Don't synthesize root/nobody when iterating. Let nss-files take care of that. If the two records
+ * are missing there, then that's fine, after all getpwent() is known to be possibly incomplete
+ * (think: LDAP/NIS type situations), and our synthesizing of root/nobody is a robustness fallback
+ * only, which matters for getpwnam()/getpwuid() primarily, which are the main NSS entrypoints to the
+ * user database. */
+ r = userdb_all(nss_glue_userdb_flags() | USERDB_DONT_SYNTHESIZE, &getpwent_data.iterator);
return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS;
}
getgrent_data.iterator = userdb_iterator_free(getgrent_data.iterator);
getpwent_data.by_membership = false;
- r = groupdb_all(nss_glue_userdb_flags(), &getgrent_data.iterator);
+ /* See _nss_systemd_setpwent() for an explanation why we use USERDB_DONT_SYNTHESIZE here */
+ r = groupdb_all(nss_glue_userdb_flags() | USERDB_DONT_SYNTHESIZE, &getgrent_data.iterator);
return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS;
}
#include <unistd.h>
#include "alloc-util.h"
+#include "blockdev-util.h"
#include "dissect-image.h"
+#include "fd-util.h"
#include "main-func.h"
#include "process-util.h"
#include "signal-util.h"
static int run(int argc, char *argv[]) {
_cleanup_free_ char *device = NULL, *type = NULL, *detected = NULL;
+ _cleanup_close_ int lock_fd = -1;
struct stat st;
int r;
/* type and device must be copied because makefs calls safe_fork, which clears argv[] */
type = strdup(argv[1]);
if (!type)
- return -ENOMEM;
+ return log_oom();
device = strdup(argv[2]);
if (!device)
- return -ENOMEM;
+ return log_oom();
if (stat(device, &st) < 0)
return log_error_errno(errno, "Failed to stat \"%s\": %m", device);
- if (!S_ISBLK(st.st_mode))
+ if (S_ISBLK(st.st_mode)) {
+ /* Lock the device so that udev doesn't interfere with our work */
+
+ lock_fd = lock_whole_block_device(st.st_rdev, LOCK_EX);
+ if (lock_fd < 0)
+ return log_error_errno(lock_fd, "Failed to lock whole block device of \"%s\": %m", device);
+ } else
log_info("%s is not a block device.", device);
r = probe_filesystem(device, &detected);
+ if (r == -EUCLEAN)
+ return log_error_errno(r, "Ambiguous results of probing for file system on \"%s\", refusing to proceed.", device);
if (r < 0)
- return log_warning_errno(r,
- r == -EUCLEAN ?
- "Cannot reliably determine probe \"%s\", refusing to proceed." :
- "Failed to probe \"%s\": %m",
- device);
-
+ return log_error_errno(r, "Failed to probe \"%s\": %m", device);
if (detected) {
- log_info("%s is not empty (type %s), exiting", device, detected);
+ log_info("'%s' is not empty (contains file system of type %s), exiting.", device, detected);
return 0;
}
EMPTY_ALLOW, /* allow empty disks, create partition table if necessary */
EMPTY_REQUIRE, /* require an empty disk, create a partition table */
EMPTY_FORCE, /* make disk empty, erase everything, create a partition table always */
+ EMPTY_CREATE, /* create disk as loopback file, create a partition table always */
} arg_empty = EMPTY_REFUSE;
static bool arg_dry_run = true;
static sd_id128_t arg_seed = SD_ID128_NULL;
static bool arg_randomize = false;
static int arg_pretty = -1;
+static uint64_t arg_size = UINT64_MAX;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
assert(p->new_size != UINT64_MAX);
m = p->new_size + span;
- xsz = partition_max_size(a->after);
+ xsz = partition_max_size(p);
if (xsz != UINT64_MAX && m > xsz)
m = xsz;
return 0;
}
-static int context_load_partition_table(Context *context, const char *node) {
+static int context_load_partition_table(
+ Context *context,
+ const char *node,
+ int *backing_fd) {
+
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
uint64_t left_boundary = UINT64_MAX, first_lba, last_lba, nsectors;
assert(context);
assert(node);
+ assert(backing_fd);
c = fdisk_new_context();
if (!c)
return log_oom();
- r = fdisk_assign_device(c, node, arg_dry_run);
+ /* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
+ * /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
+ if (*backing_fd < 0)
+ r = fdisk_assign_device(c, node, arg_dry_run);
+ else {
+ char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ xsprintf(procfs_path, "/proc/self/fd/%i", *backing_fd);
+
+ r = fdisk_assign_device(c, procfs_path, arg_dry_run);
+ }
if (r < 0)
- return log_error_errno(r, "Failed to open device: %m");
+ return log_error_errno(r, "Failed to open device '%s': %m", node);
+
+ if (*backing_fd < 0) {
+ /* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
+ *backing_fd = fcntl(fdisk_get_devfd(c), F_DUPFD_CLOEXEC, 3);
+ if (*backing_fd < 0)
+ return log_error_errno(errno, "Failed to duplicate fdisk fd: %m");
+ }
/* Tell udev not to interfere while we are processing the device */
if (flock(fdisk_get_devfd(c), arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
break;
case EMPTY_FORCE:
+ case EMPTY_CREATE:
/* Always reinitiaize the disk, don't consider what there was on the disk before */
from_scratch = true;
break;
bool z = false;
size_t c, j = 0;
- assert((c = columns()) >= 2);
+ assert_se((c = columns()) >= 2);
c -= 2; /* We do not use the leftmost and rightmost character cell */
bar = new0(Partition*, c);
if (size <= 0)
return 0;
- fd = fdisk_get_devfd(context->fdisk_context);
- assert(fd >= 0);
+ assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
if (fstat(fd, &st) < 0)
return -errno;
LIST_FOREACH(partitions, p, context->partitions) {
assert(sd_id128_is_null(p->new_uuid));
- assert(!p->new_label);
/* Never touch foreign partitions */
if (PARTITION_IS_FOREIGN(p)) {
return r;
}
+ if (p->new_label) /* Explicitly set by user? */
+ continue;
+
if (!isempty(p->current_label)) {
p->new_label = strdup(p->current_label); /* never change initialized labels */
if (!p->new_label)
if (fstat(fd, &st) < 0)
return log_error_errno(fd, "Failed to fstat() image file: %m");
if (!S_ISBLK(st.st_mode))
- return false;
+ return -ENOTBLK; /* we do not log in this one special case about errors */
if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) {
return log_error_errno(r, "Failed to write partition table: %m");
capable = device_kernel_partitions_supported(fdisk_get_devfd(context->fdisk_context));
- if (capable < 0)
+ if (capable == -ENOTBLK)
+ log_debug("Not telling kernel to reread partition table, since we are not operating on a block device.");
+ else if (capable < 0)
return capable;
- if (capable > 0) {
+ else if (capable > 0) {
log_info("Telling kernel to reread partition table.");
if (from_scratch)
" -h --help Show this help\n"
" --version Show package version\n"
" --dry-run=BOOL Whether to run dry-run operation\n"
- " --empty=MODE One of refuse, allow, require, force; controls how to\n"
- " handle empty disks lacking partition table\n"
+ " --empty=MODE One of refuse, allow, require, force, create; controls\n"
+ " how to handle empty disks lacking partition tables\n"
" --discard=BOOL Whether to discard backing blocks for new partitions\n"
" --pretty=BOOL Whether to show pretty summary before executing operation\n"
" --factory-reset=BOOL Whether to remove data partitions before recreating\n"
" --root=PATH Operate relative to root path\n"
" --definitions=DIR Find partitions in specified directory\n"
" --seed=UUID 128bit seed UUID to derive all UUIDs from\n"
+ " --size=BYTES Grow loopback file to specified size\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, ansi_highlight(), ansi_normal()
ARG_SEED,
ARG_PRETTY,
ARG_DEFINITIONS,
+ ARG_SIZE,
};
static const struct option options[] = {
{ "seed", required_argument, NULL, ARG_SEED },
{ "pretty", required_argument, NULL, ARG_PRETTY },
{ "definitions", required_argument, NULL, ARG_DEFINITIONS },
+ { "size", required_argument, NULL, ARG_SIZE },
{}
};
- int c, r;
+ int c, r, dry_run = -1;
assert(argc >= 0);
assert(argv);
if (r < 0)
return log_error_errno(r, "Failed to parse --dry-run= parameter: %s", optarg);
- arg_dry_run = r;
+ dry_run = r;
break;
case ARG_EMPTY:
arg_empty = EMPTY_REQUIRE;
else if (streq(optarg, "force"))
arg_empty = EMPTY_FORCE;
- else
+ else if (streq(optarg, "create")) {
+ arg_empty = EMPTY_CREATE;
+
+ if (dry_run < 0)
+ dry_run = false; /* Imply --dry-run=no if we create the loopback file
+ * anew. After all we cannot really break anyone's
+ * partition tables that way. */
+ } else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse --empty= parameter: %s", optarg);
break;
return r;
break;
+ case ARG_SIZE: {
+ uint64_t parsed, rounded;
+
+ r = parse_size(optarg, 1024, &parsed);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --size= parameter: %s", optarg);
+
+ rounded = round_up_size(parsed, 4096);
+ if (rounded == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too small, refusing.");
+ if (rounded == UINT64_MAX)
+ return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too large, refusing.");
+
+ if (rounded != parsed)
+ log_warning("Specified size is not a multiple of 4096, rounding up automatically. (%" PRIu64 " → %" PRIu64 ")",
+ parsed, rounded);
+
+ arg_size = rounded;
+ break;
+ }
+
case '?':
return -EINVAL;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected at most one argument, the path to the block device.");
- if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE))
+ if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Combination of --factory-reset=yes and --empty=force/--empty=require is invalid.");
+ "Combination of --factory-reset=yes and --empty=force/--empty=require/--empty=create is invalid.");
if (arg_can_factory_reset)
- arg_dry_run = true;
+ arg_dry_run = true; /* When --can-factory-reset is specified we don't make changes, hence
+ * non-dry-run mode makes no sense. Thus, imply dry run mode so that we
+ * open things strictly read-only. */
+ else if (dry_run >= 0)
+ arg_dry_run = dry_run;
+
+ if (arg_empty == EMPTY_CREATE && arg_size == UINT64_MAX)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "If --empty=create is specified, --size= must be specified, too.");
arg_node = argc > optind ? argv[optind] : NULL;
+
+ if (IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE) && !arg_node)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "A path to a device node or loopback file must be specified when --empty=force, --empty=require or --empty=create are used.");
+
return 1;
}
return 0;
}
-static int acquire_root_devno(const char *p, int mode, char **ret) {
+static int acquire_root_devno(const char *p, int mode, char **ret, int *ret_fd) {
_cleanup_close_ int fd = -1;
struct stat st;
- dev_t devno;
+ dev_t devno, fd_devno = (mode_t) -1;
int r;
+ assert(p);
+ assert(ret);
+ assert(ret_fd);
+
fd = open(p, mode);
if (fd < 0)
return -errno;
return log_oom();
*ret = s;
+ *ret_fd = TAKE_FD(fd);
+
return 0;
}
if (S_ISBLK(st.st_mode))
- devno = st.st_rdev;
+ fd_devno = devno = st.st_rdev;
else if (S_ISDIR(st.st_mode)) {
devno = st.st_dev;
-
- if (major(st.st_dev) == 0) {
+ if (major(devno) == 0) {
r = btrfs_get_block_device_fd(fd, &devno);
if (r == -ENOTTY) /* not btrfs */
return -ENODEV;
if (r < 0)
return r;
}
-
} else
return -ENOTBLK;
if (r < 0)
log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p);
- return device_path_make_canonical(S_IFBLK, devno, ret);
+ r = device_path_make_canonical(S_IFBLK, devno, ret);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p);
+
+ /* Only if we still lock at the same block device we can reuse the fd. Otherwise return an
+ * invalidated fd. */
+ *ret_fd = fd_devno != (mode_t) -1 && fd_devno == devno ? TAKE_FD(fd) : -1;
+ return 0;
}
-static int find_root(char **ret) {
+static int find_root(char **ret, int *ret_fd) {
const char *t;
int r;
+ assert(ret);
+ assert(ret_fd);
+
if (arg_node) {
- r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret);
+ if (arg_empty == EMPTY_CREATE) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *s = NULL;
+
+ s = strdup(arg_node);
+ if (!s)
+ return log_oom();
+
+ fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0777);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to create '%s': %m", arg_node);
+
+ *ret = TAKE_PTR(s);
+ *ret_fd = TAKE_FD(fd);
+ return 0;
+ }
+
+ r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret, ret_fd);
if (r < 0)
return log_error_errno(r, "Failed to determine backing device of %s: %m", arg_node);
return 0;
}
+ assert(IN_SET(arg_empty, EMPTY_REFUSE, EMPTY_ALLOW));
+
/* Let's search for the root device. We look for two cases here: first in /, and then in /usr. The
* latter we check for cases where / is a tmpfs and only /usr is an actual persistent block device
* (think: volatile setups) */
} else
p = t;
- r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret);
+ r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret, ret_fd);
if (r < 0) {
if (r != -ENODEV)
return log_error_errno(r, "Failed to determine backing device of %s: %m", p);
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device.");
}
+static int resize_backing_fd(const char *node, int *fd) {
+ char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
+ _cleanup_close_ int writable_fd = -1;
+ struct stat st;
+ int r;
+
+ assert(node);
+ assert(fd);
+
+ if (arg_size == UINT64_MAX) /* Nothing to do */
+ return 0;
+
+ if (*fd < 0) {
+ /* Open the file if we haven't opened it yet. Note that we open it read-only here, just to
+ * keep a reference to the file we can pass around. */
+ *fd = open(node, O_RDONLY|O_CLOEXEC);
+ if (*fd < 0)
+ return log_error_errno(errno, "Failed to open '%s' in order to adjust size: %m", node);
+ }
+
+ if (fstat(*fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat '%s': %m", node);
+
+ r = stat_verify_regular(&st);
+ if (r < 0)
+ return log_error_errno(r, "Specified path '%s' is not a regular file, cannot resize: %m", node);
+
+ assert_se(format_bytes(buf1, sizeof(buf1), st.st_size));
+ assert_se(format_bytes(buf2, sizeof(buf2), arg_size));
+
+ if ((uint64_t) st.st_size >= arg_size) {
+ log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)", node, buf1, buf2);
+ return 0;
+ }
+
+ /* The file descriptor is read-only. In order to grow the file we need to have a writable fd. We
+ * reopen the file for that temporarily. We keep the writable fd only open for this operation though,
+ * as fdisk can't accept it anyway. */
+
+ writable_fd = fd_reopen(*fd, O_WRONLY|O_CLOEXEC);
+ if (writable_fd < 0)
+ return log_error_errno(writable_fd, "Failed to reopen backing file '%s' writable: %m", node);
+
+ if (!arg_discard) {
+ if (fallocate(writable_fd, 0, 0, arg_size) < 0) {
+ if (!ERRNO_IS_NOT_SUPPORTED(errno))
+ return log_error_errno(errno, "Failed to grow '%s' from %s to %s by allocation: %m",
+ node, buf1, buf2);
+
+ /* Fallback to truncation, if fallocate() is not supported. */
+ log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
+ } else {
+ if (st.st_size == 0) /* Likely regular file just created by us */
+ log_info("Allocated %s for '%s'.", buf2, node);
+ else
+ log_info("File '%s' grown from %s to %s by allocation.", node, buf1, buf2);
+
+ return 1;
+ }
+ }
+
+ if (ftruncate(writable_fd, arg_size) < 0)
+ return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
+ node, buf1, buf2);
+
+ if (st.st_size == 0) /* Likely regular file just created by us */
+ log_info("Sized '%s' to %s.", node, buf2);
+ else
+ log_info("File '%s' grown from %s to %s by truncation.", node, buf1, buf2);
+
+ return 1;
+}
+
static int run(int argc, char *argv[]) {
_cleanup_(context_freep) Context* context = NULL;
_cleanup_free_ char *node = NULL;
+ _cleanup_close_ int backing_fd = -1;
bool from_scratch;
int r;
if (r < 0)
return r;
- if (context->n_partitions <= 0 && arg_empty != EMPTY_FORCE)
+ if (context->n_partitions <= 0 && arg_empty == EMPTY_REFUSE) {
+ log_info("Didn't find any partition definition files, nothing to do.");
return 0;
+ }
- r = find_root(&node);
+ r = find_root(&node, &backing_fd);
if (r < 0)
return r;
- r = context_load_partition_table(context, node);
+ if (arg_size != UINT64_MAX) {
+ r = resize_backing_fd(node, &backing_fd);
+ if (r < 0)
+ return r;
+ }
+
+ r = context_load_partition_table(context, node, &backing_fd);
if (r == -EHWPOISON)
return 77; /* Special return value which means "Not GPT, so not doing anything". This isn't
* really an error when called at boot. */
/* Reload the reduced partition table */
context_unload_partition_table(context);
- r = context_load_partition_table(context, node);
+ r = context_load_partition_table(context, node, &backing_fd);
if (r < 0)
return r;
}
trap "rm -rf '$D'" EXIT INT QUIT PIPE
mkdir -p $D/definitions
-truncate -s 1G $D/zzz
-
SEED=e2a40bf9-73f1-4278-9160-49c031e7aef8
-$repart $D/zzz --empty=force --dry-run=no --seed=$SEED
+$repart $D/zzz --empty=create --size=1G --seed=$SEED
sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' > $D/empty
$D/zzz5 : start= 1908696, size= 188416, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=03477476-06AD-44E8-9EF4-BC2BD7771289, name="linux-generic"
EOF
-truncate -s 2G $D/zzz
-
-$repart $D/zzz --dry-run=no --seed=$SEED --definitions=$D/definitions
+$repart $D/zzz --size=2G --dry-run=no --seed=$SEED --definitions=$D/definitions
sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' >$D/populated3
const char *name,
int fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control = {};
struct iovec iovec;
struct msghdr mh = {
.msg_control = &control,
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &data_fd, sizeof(int));
- mh.msg_controllen = CMSG_SPACE(sizeof(int));
iovec = IOVEC_MAKE_STRING(name);
if (sendmsg(socket_fd, &mh, MSG_NOSIGNAL) < 0)
char **ret_name,
int *ret_fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
char buffer[PATH_MAX+2];
struct iovec iov = IOVEC_INIT(buffer, sizeof(buffer)-1);
struct msghdr mh = {
assert(ret_name);
assert(ret_fd);
- n = recvmsg(socket_fd, &mh, MSG_CMSG_CLOEXEC);
+ n = recvmsg_safe(socket_fd, &mh, MSG_CMSG_CLOEXEC);
if (n < 0)
- return -errno;
+ return (int) n;
CMSG_FOREACH(cmsg, &mh) {
if (cmsg->cmsg_level == SOL_SOCKET &&
return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
}
- unit_files = set_new(&string_hash_ops);
- if (!unit_files)
- return -ENOMEM;
-
markers = set_new(&path_hash_ops);
if (!markers)
return -ENOMEM;
continue;
/* Filter out duplicates */
- if (set_get(unit_files, de->d_name))
+ if (set_contains(unit_files, de->d_name))
continue;
dirent_ensure_type(d, de);
if (r > 0)
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active, can't detach.", de->d_name);
- r = set_put_strdup(unit_files, de->d_name);
+ r = set_put_strdup(&unit_files, de->d_name);
if (r < 0)
return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name);
_cleanup_(lookup_paths_free) LookupPaths paths = {};
bool found_enabled = false, found_running = false;
- _cleanup_set_free_free_ Set *unit_files = NULL;
+ _cleanup_set_free_ Set *unit_files = NULL;
_cleanup_closedir_ DIR *d = NULL;
const char *where;
struct dirent *de;
return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
}
- unit_files = set_new(&string_hash_ops);
- if (!unit_files)
- return -ENOMEM;
-
FOREACH_DIRENT(de, d, return log_debug_errno(errno, "Failed to enumerate '%s' directory: %m", where)) {
UnitFileState state;
continue;
/* Filter out duplicates */
- if (set_get(unit_files, de->d_name))
+ if (set_contains(unit_files, de->d_name))
continue;
dirent_ensure_type(d, de);
if (r > 0)
found_running = true;
- r = set_put_strdup(unit_files, de->d_name);
+ r = set_put_strdup(&unit_files, de->d_name);
if (r < 0)
return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name);
}
if (r < 0)
return r;
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "GetImageMetadata");
+ r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "GetImageMetadata");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Could not watch jobs: %m");
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "GetImageMetadata");
+ r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "GetImageMetadata");
if (r < 0)
return bus_log_create_error(r);
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "AttachImage");
+ r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "AttachImage");
if (r < 0)
return bus_log_create_error(r);
(void) maybe_stop_disable(bus, image, argv);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "DetachImage",
- &error,
- &reply,
- "sb", image, arg_runtime);
+ r = bus_call_method(bus, bus_portable_mgr, "DetachImage", &error, &reply, "sb", image, arg_runtime);
if (r < 0)
return log_error_errno(r, "Failed to detach image: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "ListImages",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_portable_mgr, "ListImages", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r));
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "RemoveImage");
+ r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "RemoveImage");
if (r < 0)
return bus_log_create_error(r);
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "MarkImageReadOnly",
- &error,
- NULL,
- "sb", argv[1], b);
+ r = bus_call_method(bus, bus_portable_mgr, "MarkImageReadOnly", &error, NULL, "sb", argv[1], b);
if (r < 0)
return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, r));
if (argc > 2)
/* With two arguments changes the quota limit of the specified image */
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "SetImageLimit",
- &error,
- NULL,
- "st", argv[1], limit);
+ r = bus_call_method(bus, bus_portable_mgr, "SetImageLimit", &error, NULL, "st", argv[1], limit);
else
/* With one argument changes the pool quota limit */
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "SetPoolLimit",
- &error,
- NULL,
- "t", limit);
+ r = bus_call_method(bus, bus_portable_mgr, "SetPoolLimit", &error, NULL, "t", limit);
if (r < 0)
return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "GetImageState",
- &error,
- &reply,
- "s", image);
+ r = bus_call_method(bus, bus_portable_mgr, "GetImageState", &error, &reply, "s", image);
if (r < 0)
return log_error_errno(r, "Failed to get image state: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_get_property_strv(
- bus,
- "org.freedesktop.portable1",
- "/org/freedesktop/portable1",
- "org.freedesktop.portable1.Manager",
- "Profiles",
- &error,
- &l);
+ r = bus_get_property_strv(bus, bus_portable_mgr, "Profiles", &error, &l);
if (r < 0)
return log_error_errno(r, "Failed to acquire list of profiles: %s", bus_error_message(&error, r));
resolved-etc-hosts.h
resolved-etc-hosts.c
resolved-dnstls.h
- resolved-util.c
- resolved-util.h
'''.split())
resolvectl_sources = files('''
[],
[],
'ENABLE_RESOLVE', 'manual'],
-
- [['src/resolve/test-resolved-util.c',
- 'src/resolve/resolved-util.c',
- 'src/resolve/resolved-util.h'],
- [],
- []],
]
log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveHostname");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
if (r < 0)
return bus_log_create_error(r);
log_debug("Resolving %s.", pretty);
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveAddress");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
if (r < 0)
return bus_log_create_error(r);
log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname);
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveRecord");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord");
if (r < 0)
return bus_log_create_error(r);
else
log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResolveService");
+ r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveService");
if (r < 0)
return bus_log_create_error(r);
assert(bus);
- r = sd_bus_get_property_trivial(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "DNSSECSupported",
- &error,
- 'b',
- &dnssec_supported);
+ r = bus_get_property_trivial(bus, bus_resolve_mgr, "DNSSECSupported", &error, 'b', &dnssec_supported);
if (r < 0)
return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
yes_no(dnssec_supported),
ansi_normal());
- r = sd_bus_get_property(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "TransactionStatistics",
- &error,
- &reply,
- "(tt)");
+ r = bus_get_property(bus, bus_resolve_mgr, "TransactionStatistics", &error, &reply, "(tt)");
if (r < 0)
return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
reply = sd_bus_message_unref(reply);
- r = sd_bus_get_property(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "CacheStatistics",
- &error,
- &reply,
- "(ttt)");
+ r = bus_get_property(bus, bus_resolve_mgr, "CacheStatistics", &error, &reply, "(ttt)");
if (r < 0)
return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
reply = sd_bus_message_unref(reply);
- r = sd_bus_get_property(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "DNSSECStatistics",
- &error,
- &reply,
- "(tttt)");
+ r = bus_get_property(bus, bus_resolve_mgr, "DNSSECStatistics", &error, &reply, "(tttt)");
if (r < 0)
return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
sd_bus *bus = userdata;
int r;
- r = sd_bus_call_method(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResetStatistics",
- &error,
- NULL,
- NULL);
+ r = bus_call_method(bus, bus_resolve_mgr, "ResetStatistics", &error, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
sd_bus *bus = userdata;
int r;
- r = sd_bus_call_method(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "FlushCaches",
- &error,
- NULL,
- NULL);
+ r = bus_call_method(bus, bus_resolve_mgr, "FlushCaches", &error, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
sd_bus *bus = userdata;
int r;
- r = sd_bus_call_method(bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "ResetServerFeatures",
- &error,
- NULL,
- NULL);
+ r = bus_call_method(bus, bus_resolve_mgr, "ResetServerFeatures", &error, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
return r;
}
-static int call_dns(sd_bus *bus, char **dns, const char *destination, const char *path, const char *interface, sd_bus_error *error) {
+static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
char **p;
int r;
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- destination,
- path,
- interface,
- "SetLinkDNS");
+ r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNS");
if (r < 0)
return bus_log_create_error(r);
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
- r = call_dns(bus, argv + 2,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- &error);
+ r = call_dns(bus, argv + 2, bus_resolve_mgr, &error);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = call_dns(bus, argv + 2,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- &error);
+ r = call_dns(bus, argv + 2, bus_network_mgr, &error);
}
if (r < 0) {
if (arg_ifindex_permissive &&
return 0;
}
-static int call_domain(sd_bus *bus, char **domain, const char *destination, const char *path, const char *interface, sd_bus_error *error) {
+static int call_domain(sd_bus *bus, char **domain, const BusLocator *locator, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
char **p;
int r;
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- destination,
- path,
- interface,
- "SetLinkDomains");
+ r = bus_message_new_method_call(bus, &req, locator, "SetLinkDomains");
if (r < 0)
return bus_log_create_error(r);
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL);
- r = call_domain(bus, argv + 2,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- &error);
+ r = call_domain(bus, argv + 2, bus_resolve_mgr, &error);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = call_domain(bus, argv + 2,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- &error);
+ r = call_domain(bus, argv + 2, bus_network_mgr, &error);
}
if (r < 0) {
if (arg_ifindex_permissive &&
if (b < 0)
return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "SetLinkDefaultRoute",
- &error,
- NULL,
- "ib", arg_ifindex, b);
+ r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "SetLinkDefaultRoute",
- &error,
- NULL,
- "ib", arg_ifindex, b);
+ r = bus_call_method(bus, bus_network_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
}
if (r < 0) {
if (arg_ifindex_permissive &&
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "SetLinkLLMNR",
- &error,
- NULL,
- "is", arg_ifindex, argv[2]);
+ r = bus_call_method(bus, bus_resolve_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "SetLinkLLMNR",
- &error,
- NULL,
- "is", arg_ifindex, argv[2]);
+ r = bus_call_method(bus, bus_network_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
}
if (r < 0) {
if (arg_ifindex_permissive &&
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "SetLinkMulticastDNS",
- &error,
- NULL,
- "is", arg_ifindex, argv[2]);
+ r = bus_call_method(bus, bus_resolve_mgr, "SetLinkMulticastDNS", &error, NULL, "is", arg_ifindex, argv[2]);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
+ bus_network_mgr,
"SetLinkMulticastDNS",
&error,
NULL,
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "SetLinkDNSOverTLS",
- &error,
- NULL,
- "is", arg_ifindex, argv[2]);
+ r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSOverTLS", &error, NULL, "is", arg_ifindex, argv[2]);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
+ bus_network_mgr,
"SetLinkDNSOverTLS",
&error,
NULL,
if (argc < 3)
return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "SetLinkDNSSEC",
- &error,
- NULL,
- "is", arg_ifindex, argv[2]);
+ r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "SetLinkDNSSEC",
- &error,
- NULL,
- "is", arg_ifindex, argv[2]);
+ r = bus_call_method(bus, bus_network_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
}
if (r < 0) {
if (arg_ifindex_permissive &&
return 0;
}
-static int call_nta(sd_bus *bus, char **nta, const char *destination, const char *path, const char *interface, sd_bus_error *error) {
+static int call_nta(sd_bus *bus, char **nta, const BusLocator *locator, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
int r;
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- destination,
- path,
- interface,
- "SetLinkDNSSECNegativeTrustAnchors");
+ r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNSSECNegativeTrustAnchors");
if (r < 0)
return bus_log_create_error(r);
}
}
- r = call_nta(bus, clear ? NULL : argv + 2,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- &error);
+ r = call_nta(bus, clear ? NULL : argv + 2, bus_resolve_mgr, &error);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = call_nta(bus, clear ? NULL : argv + 2,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- &error);
+ r = call_nta(bus, clear ? NULL : argv + 2, bus_network_mgr, &error);
}
if (r < 0) {
if (arg_ifindex_permissive &&
if (arg_ifindex <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Interface argument required.");
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.resolve1",
- "/org/freedesktop/resolve1",
- "org.freedesktop.resolve1.Manager",
- "RevertLink",
- &error,
- NULL,
- "i", arg_ifindex);
+ r = bus_call_method(bus, bus_resolve_mgr, "RevertLink", &error, NULL, "i", arg_ifindex);
if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
sd_bus_error_free(&error);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "RevertLinkDNS",
- &error,
- NULL,
- "i", arg_ifindex);
+ r = bus_call_method(bus, bus_network_mgr, "RevertLinkDNS", &error, NULL, "i", arg_ifindex);
}
if (r < 0) {
if (arg_ifindex_permissive &&
if (has_root_domain && found <= 0) {
/* If there's exactly one SRV RR and it uses
- * the root domain as host name, then the
+ * the root domain as hostname, then the
* service is explicitly not offered on the
* domain. Report this as a recognizable
* error. See RFC 2782, Section "Usage
SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", bus_property_get_ntas, 0, 0),
SD_BUS_PROPERTY("DNSStubListener", "s", bus_property_get_dns_stub_listener_mode, offsetof(Manager, dns_stub_listener_mode), 0),
- SD_BUS_METHOD_WITH_NAMES("ResolveHostname",
- "isit",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(name)
- SD_BUS_PARAM(family)
- SD_BUS_PARAM(flags),
- "a(iiay)st",
- SD_BUS_PARAM(addresses)
- SD_BUS_PARAM(canonical)
- SD_BUS_PARAM(flags),
- bus_method_resolve_hostname,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("ResolveAddress",
- "iiayt",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(family)
- SD_BUS_PARAM(address)
- SD_BUS_PARAM(flags),
- "a(is)t",
- SD_BUS_PARAM(names)
- SD_BUS_PARAM(flags),
- bus_method_resolve_address,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("ResolveRecord",
- "isqqt",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(name)
- SD_BUS_PARAM(class)
- SD_BUS_PARAM(type)
- SD_BUS_PARAM(flags),
- "a(iqqay)t",
- SD_BUS_PARAM(records)
- SD_BUS_PARAM(flags),
- bus_method_resolve_record,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("ResolveService",
- "isssit",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(name)
- SD_BUS_PARAM(type)
- SD_BUS_PARAM(domain)
- SD_BUS_PARAM(family)
- SD_BUS_PARAM(flags),
- "a(qqqsa(iiay)s)aayssst",
- SD_BUS_PARAM(srv_data)
- SD_BUS_PARAM(txt_data)
- SD_BUS_PARAM(canonical_name)
- SD_BUS_PARAM(canonical_type)
- SD_BUS_PARAM(canonical_domain)
- SD_BUS_PARAM(flags),
- bus_method_resolve_service,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("GetLink",
- "i",
- SD_BUS_PARAM(ifindex),
- "o",
- SD_BUS_PARAM(path),
- bus_method_get_link,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkDNS",
- "ia(iay)",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(addresses),
- NULL,,
- bus_method_set_link_dns_servers,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkDomains",
- "ia(sb)",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(domains),
- NULL,,
- bus_method_set_link_domains,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkDefaultRoute",
- "ib",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(enable),
- NULL,,
- bus_method_set_link_default_route,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkLLMNR",
- "is",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(mode),
- NULL,,
- bus_method_set_link_llmnr,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkMulticastDNS",
- "is",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(mode),
- NULL,,
- bus_method_set_link_mdns,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkDNSOverTLS",
- "is",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(mode),
- NULL,,
- bus_method_set_link_dns_over_tls,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkDNSSEC",
- "is",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(mode),
- NULL,,
- bus_method_set_link_dnssec,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLinkDNSSECNegativeTrustAnchors",
- "ias",
- SD_BUS_PARAM(ifindex)
- SD_BUS_PARAM(names),
- NULL,,
- bus_method_set_link_dnssec_negative_trust_anchors,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("RevertLink",
- "i",
- SD_BUS_PARAM(ifindex),
- NULL,,
- bus_method_revert_link,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("RegisterService",
- "sssqqqaa{say}",
- SD_BUS_PARAM(name)
- SD_BUS_PARAM(name_template)
- SD_BUS_PARAM(type)
- SD_BUS_PARAM(service_port)
- SD_BUS_PARAM(service_priority)
- SD_BUS_PARAM(serwise_weight)
- SD_BUS_PARAM(txt_datas),
- "o",
- SD_BUS_PARAM(service_path),
- bus_method_register_service,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("UnregisterService",
- "o",
- SD_BUS_PARAM(service_path),
- NULL,,
- bus_method_unregister_service,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_METHOD("ResetStatistics",
- NULL,
- NULL,
- bus_method_reset_statistics,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("FlushCaches",
- NULL,
- NULL,
- bus_method_flush_caches,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResetServerFeatures",
- NULL,
- NULL,
- bus_method_reset_server_features,
- SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ResolveHostname",
+ SD_BUS_ARGS("i", ifindex, "s", name, "i", family, "t", flags),
+ SD_BUS_RESULT("a(iiay)", addresses, "s", canonical, "t", flags),
+ bus_method_resolve_hostname,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ResolveAddress",
+ SD_BUS_ARGS("i", ifindex, "i", family, "ay", address, "t", flags),
+ SD_BUS_RESULT("a(is)", names, "t", flags),
+ bus_method_resolve_address,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ResolveRecord",
+ SD_BUS_ARGS("i", ifindex, "s", name, "q", class, "q", type, "t", flags),
+ SD_BUS_RESULT("a(iqqay)", records, "t", flags),
+ bus_method_resolve_record,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ResolveService",
+ SD_BUS_ARGS("i", ifindex,
+ "s", name,
+ "s", type,
+ "s", domain,
+ "i", family,
+ "t", flags),
+ SD_BUS_RESULT("a(qqqsa(iiay)s)", srv_data,
+ "aay", txt_data,
+ "s", canonical_name,
+ "s", canonical_type,
+ "s", canonical_domain,
+ "t", flags),
+ bus_method_resolve_service,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("GetLink",
+ SD_BUS_ARGS("i", ifindex),
+ SD_BUS_RESULT("o", path),
+ bus_method_get_link,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkDNS",
+ SD_BUS_ARGS("i", ifindex, "a(iay)", addresses),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_dns_servers,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkDomains",
+ SD_BUS_ARGS("i", ifindex, "a(sb)", domains),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_domains,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkDefaultRoute",
+ SD_BUS_ARGS("i", ifindex, "b", enable),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_default_route,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkLLMNR",
+ SD_BUS_ARGS("i", ifindex, "s", mode),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_llmnr,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkMulticastDNS",
+ SD_BUS_ARGS("i", ifindex, "s", mode),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_mdns,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkDNSOverTLS",
+ SD_BUS_ARGS("i", ifindex, "s", mode),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_dns_over_tls,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSEC",
+ SD_BUS_ARGS("i", ifindex, "s", mode),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_dnssec,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSECNegativeTrustAnchors",
+ SD_BUS_ARGS("i", ifindex, "as", names),
+ SD_BUS_NO_RESULT,
+ bus_method_set_link_dnssec_negative_trust_anchors,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("RevertLink",
+ SD_BUS_ARGS("i", ifindex),
+ SD_BUS_NO_RESULT,
+ bus_method_revert_link,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("RegisterService",
+ SD_BUS_ARGS("s", name,
+ "s", name_template,
+ "s", type,
+ "q", service_port,
+ "q", service_priority,
+ "q", service_weight,
+ "aa{say}", txt_datas),
+ SD_BUS_RESULT("o", service_path),
+ bus_method_register_service,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("UnregisterService",
+ SD_BUS_ARGS("o", service_path),
+ SD_BUS_NO_RESULT,
+ bus_method_unregister_service,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ResetStatistics",
+ SD_BUS_NO_ARGS,
+ SD_BUS_NO_RESULT,
+ bus_method_reset_statistics,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("FlushCaches",
+ SD_BUS_NO_ARGS,
+ SD_BUS_NO_RESULT,
+ bus_method_flush_caches,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ResetServerFeatures",
+ SD_BUS_NO_ARGS,
+ SD_BUS_NO_RESULT,
+ bus_method_reset_server_features,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
+const BusObjectImplementation manager_object = {
+ "/org/freedesktop/resolve1",
+ "org.freedesktop.resolve1.Manager",
+ .vtables = BUS_VTABLES(resolve_vtable),
+ .children = BUS_IMPLEMENTATIONS(&link_object,
+ &dnssd_object),
+};
+
static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
int b, r;
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
- r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register object: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/link", "org.freedesktop.resolve1.Link", link_vtable, link_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register link objects: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/link", link_node_enumerator, m);
+ r = bus_add_implementation(m->bus, &manager_object, m);
if (r < 0)
- return log_error_errno(r, "Failed to register link enumerator: %m");
-
- r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/dnssd", "org.freedesktop.resolve1.DnssdService", dnssd_vtable, dnssd_object_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register dnssd objects: %m");
-
- r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/dnssd", dnssd_node_enumerator, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register dnssd enumerator: %m");
+ return r;
r = bus_log_control_api_register(m->bus);
if (r < 0)
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "bus-util.h"
#include "resolved-manager.h"
+extern const BusObjectImplementation manager_object;
+
int manager_connect_bus(Manager *m);
int _manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
#define manager_send_changed(manager, ...) _manager_send_changed(manager, __VA_ARGS__, NULL)
#include "parse-util.h"
#include "resolved-conf.h"
#include "resolved-dnssd.h"
-#include "resolved-util.h"
+#include "resolved-manager.h"
+#include "resolved-dns-search-domain.h"
+#include "dns-domain.h"
+#include "socket-netlink.h"
#include "specifier.h"
#include "string-table.h"
#include "string-util.h"
int config_parse_dnssd_service_name(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
static const Specifier specifier_table[] = {
+ { 'm', specifier_machine_id, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'H', specifier_host_name, NULL },
- { 'm', specifier_machine_id, NULL },
{ 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
{}
};
DnssdService *s = userdata;
_DNS_STUB_LISTENER_MODE_INVALID = -1
};
-#include "resolved-manager.h"
#include "resolved-dns-server.h"
int manager_parse_config_file(Manager *m);
#include "resolved-dns-answer.h"
#include "resolved-dns-question.h"
-#include "resolved-dns-stream.h"
#include "resolved-dns-search-domain.h"
+#include "resolved-dns-transaction.h"
struct DnsQueryCandidate {
DnsQuery *query;
#pragma once
#include "list.h"
+#include "ratelimit.h"
+typedef struct DnsQueryCandidate DnsQueryCandidate;
typedef struct DnsScope DnsScope;
#include "resolved-dns-cache.h"
#include "resolved-dns-dnssec.h"
#include "resolved-dns-packet.h"
-#include "resolved-dns-query.h"
+
#include "resolved-dns-search-domain.h"
#include "resolved-dns-server.h"
#include "resolved-dns-stream.h"
#include "resolved-dns-zone.h"
-#include "resolved-link.h"
typedef enum DnsScopeMatch {
DNS_SCOPE_NO,
#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-search-domain.h"
+#include "resolved-link.h"
+#include "resolved-manager.h"
int dns_search_domain_new(
Manager *m,
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "list.h"
#include "macro.h"
typedef struct DnsSearchDomain DnsSearchDomain;
+typedef struct Link Link;
+typedef struct Manager Manager;
typedef enum DnsSearchDomainType {
DNS_SEARCH_DOMAIN_SYSTEM,
DNS_SEARCH_DOMAIN_LINK,
} DnsSearchDomainType;
-#include "resolved-link.h"
-#include "resolved-manager.h"
-
struct DnsSearchDomain {
Manager *manager;
#include "resolved-bus.h"
#include "resolved-dns-server.h"
#include "resolved-dns-stub.h"
+#include "resolved-manager.h"
#include "resolved-resolv-conf.h"
#include "siphash24.h"
#include "string-table.h"
#pragma once
#include "in-addr-util.h"
+#include "list.h"
+#include "resolve-util.h"
+#include "time-util.h"
+typedef struct DnsScope DnsScope;
typedef struct DnsServer DnsServer;
+typedef struct DnsStream DnsStream;
+typedef struct DnsPacket DnsPacket;
+typedef struct Link Link;
+typedef struct Manager Manager;
+
+#include "resolved-dnstls.h"
typedef enum DnsServerType {
DNS_SERVER_SYSTEM,
const char* dns_server_feature_level_to_string(int i) _const_;
int dns_server_feature_level_from_string(const char *s) _pure_;
-#include "resolved-dnstls.h"
-#include "resolved-link.h"
-#include "resolved-manager.h"
-
struct DnsServer {
Manager *manager;
#include "io-util.h"
#include "missing_network.h"
#include "resolved-dns-stream.h"
+#include "resolved-manager.h"
#define DNS_STREAM_TIMEOUT_USEC (10 * USEC_PER_SEC)
#define DNS_STREAMS_MAX 128
}
static int dns_stream_identify(DnsStream *s) {
- union {
- struct cmsghdr header; /* For alignment */
- uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
- + EXTRA_CMSG_SPACE /* kernel appears to require extra space */];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
+ + EXTRA_CMSG_SPACE /* kernel appears to require extra space */) control;
struct msghdr mh = {};
struct cmsghdr *cmsg;
socklen_t sl;
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "sd-event.h"
+
+#include "ordered-set.h"
#include "socket-util.h"
+typedef struct DnsServer DnsServer;
typedef struct DnsStream DnsStream;
+typedef struct DnsTransaction DnsTransaction;
+typedef struct Manager Manager;
+
+#include "resolved-dns-packet.h"
+#include "resolved-dnstls.h"
typedef enum DnsStreamType {
DNS_STREAM_LOOKUP, /* Outgoing connection to a classic DNS server */
_DNS_STREAM_TYPE_INVALID = -1,
} DnsStreamType;
-#include "resolved-dns-packet.h"
-#include "resolved-dns-transaction.h"
-#include "resolved-dnstls.h"
-#include "resolved-manager.h"
-
#define DNS_STREAM_WRITE_TLS_DATA 1
/* Streams are used by three subsystems:
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "sd-event.h"
+
typedef struct DnsTransaction DnsTransaction;
typedef enum DnsTransactionState DnsTransactionState;
typedef enum DnsTransactionSource DnsTransactionSource;
+#include "resolved-dns-answer.h"
+#include "resolved-dns-dnssec.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-question.h"
+#include "resolved-dns-server.h"
+
enum DnsTransactionState {
DNS_TRANSACTION_NULL,
DNS_TRANSACTION_PENDING,
_DNS_TRANSACTION_SOURCE_INVALID = -1
};
-#include "resolved-dns-answer.h"
-#include "resolved-dns-packet.h"
-#include "resolved-dns-question.h"
-#include "resolved-dns-scope.h"
-#include "resolved-dns-server.h"
-#include "resolved-dns-stream.h"
-
struct DnsTransaction {
DnsScope *scope;
* unsigned. */
NULSTR_FOREACH(name, private_domains) {
-
if (dns_trust_anchor_knows_domain_positive(d, name))
continue;
- r = set_put_strdup(d->negative_by_name, name);
+ r = set_put_strdup(&d->negative_by_name, name);
if (r < 0)
return r;
}
#include "resolved-dns-packet.h"
#include "resolved-dns-zone.h"
#include "resolved-dnssd.h"
+#include "resolved-manager.h"
#include "string-util.h"
/* Never allow more than 1K entries */
#include "resolved-dnssd-bus.h"
#include "resolved-dnssd.h"
#include "resolved-link.h"
+#include "resolved-manager.h"
#include "strv.h"
#include "user-util.h"
return sd_bus_reply_method_return(message, NULL);
}
-const sd_bus_vtable dnssd_vtable[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_METHOD("Unregister", NULL, NULL, bus_dnssd_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_SIGNAL("Conflicted", NULL, 0),
-
- SD_BUS_VTABLE_END
-};
-
-int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *name = NULL;
Manager *m = userdata;
DnssdService *service;
return 1;
}
-int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
DnssdService *service;
return 1;
}
+
+static const sd_bus_vtable dnssd_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+
+ SD_BUS_METHOD("Unregister", NULL, NULL, bus_dnssd_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_SIGNAL("Conflicted", NULL, 0),
+
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation dnssd_object = {
+ "/org/freedesktop/resolve1/dnssd",
+ "org.freedesktop.resolve1.DnssdService",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({dnssd_vtable, dnssd_object_find}),
+ .node_enumerator = dnssd_node_enumerator,
+};
#include "sd-bus.h"
-extern const sd_bus_vtable dnssd_vtable[];
+#include "bus-util.h"
-int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
-int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
+extern const BusObjectImplementation dnssd_object;
int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error);
int dnssd_render_instance_name(DnssdService *s, char **ret_name) {
static const Specifier specifier_table[] = {
+ { 'm', specifier_machine_id, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'H', specifier_dnssd_host_name, NULL },
- { 'm', specifier_machine_id, NULL },
{ 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
{}
};
_cleanup_free_ char *name = NULL;
#include "resolved-dns-stream.h"
#include "resolved-dnstls.h"
+#include "resolved-manager.h"
#define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit);
}
int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
- _cleanup_(gnutls_deinitp) gnutls_session_t gs;
+ _cleanup_(gnutls_deinitp) gnutls_session_t gs = NULL;
int r;
assert(stream);
#include "io-util.h"
#include "resolved-dns-stream.h"
#include "resolved-dnstls.h"
+#include "resolved-manager.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(SSL*, SSL_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(BIO*, BIO_free);
#if ENABLE_DNS_OVER_TLS
+#include <stdint.h>
+
+typedef struct DnsServer DnsServer;
+typedef struct DnsStream DnsStream;
typedef struct DnsTlsManagerData DnsTlsManagerData;
typedef struct DnsTlsServerData DnsTlsServerData;
typedef struct DnsTlsStreamData DnsTlsStreamData;
+typedef struct Manager Manager;
#if DNS_OVER_TLS_USE_GNUTLS
#include "resolved-dnstls-gnutls.h"
#error Unknown dependency for supporting DNS-over-TLS
#endif
-#include "resolved-dns-stream.h"
-#include "resolved-dns-transaction.h"
-#include "resolved-manager.h"
-
#define DNSTLS_STREAM_CLOSED 1
int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server);
r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX);
if (r < 0)
- return log_error_errno(r, "/etc/hosts:%u: couldn't extract host name: %m", nr);
+ return log_error_errno(r, "/etc/hosts:%u: couldn't extract hostname: %m", nr);
if (r == 0)
break;
}
if (!found)
- log_warning("/etc/hosts:%u: line is missing any host names", nr);
+ log_warning("/etc/hosts:%u: line is missing any hostnames", nr);
return 0;
}
#include <stddef.h>
#include "conf-parser.h"
#include "resolved-conf.h"
+#include "resolved-manager.h"
%}
struct ConfigPerfItem;
%null_strings
Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
-Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
\ No newline at end of file
+Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid negative trust anchor domain: %s", *i);
- r = set_put_strdup(ns, *i);
+ r = set_put_strdup(&ns, *i);
if (r < 0)
return r;
}
return sd_bus_reply_method_return(message, NULL);
}
-const sd_bus_vtable link_vtable[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
- SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
- SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
- SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
- SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
- SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
- SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
- SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
- SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
- SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
- SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
-
- SD_BUS_METHOD_WITH_NAMES("SetDNS",
- "a(iay)",
- SD_BUS_PARAM(addresses),
- NULL,,
- bus_link_method_set_dns_servers,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetDomains",
- "a(sb)",
- SD_BUS_PARAM(domains),
- NULL,,
- bus_link_method_set_domains,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetDefaultRoute",
- "b",
- SD_BUS_PARAM(enable),
- NULL,,
- bus_link_method_set_default_route,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetLLMNR",
- "s",
- SD_BUS_PARAM(mode),
- NULL,,
- bus_link_method_set_llmnr,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetMulticastDNS",
- "s",
- SD_BUS_PARAM(mode),
- NULL,,
- bus_link_method_set_mdns,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetDNSOverTLS",
- "s",
- SD_BUS_PARAM(mode),
- NULL,,
- bus_link_method_set_dns_over_tls,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetDNSSEC",
- "s",
- SD_BUS_PARAM(mode),
- NULL,,
- bus_link_method_set_dnssec,
- SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD_WITH_NAMES("SetDNSSECNegativeTrustAnchors",
- "as",
- SD_BUS_PARAM(names),
- NULL,,
- bus_link_method_set_dnssec_negative_trust_anchors,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_VTABLE_END
-};
-
-int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
+static int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *e = NULL;
Manager *m = userdata;
Link *link;
return p;
}
-int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
Link *link;
return 1;
}
+
+static const sd_bus_vtable link_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+
+ SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
+ SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
+ SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
+ SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
+ SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
+ SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
+ SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
+ SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
+ SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
+ SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
+ SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
+
+ SD_BUS_METHOD_WITH_ARGS("SetDNS",
+ SD_BUS_ARGS("a(iay)", addresses),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_dns_servers,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetDomains",
+ SD_BUS_ARGS("a(sb)", domains),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_domains,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute",
+ SD_BUS_ARGS("b", enable),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_default_route,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLLMNR",
+ SD_BUS_ARGS("s", mode),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_llmnr,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS",
+ SD_BUS_ARGS("s", mode),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_mdns,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS",
+ SD_BUS_ARGS("s", mode),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_dns_over_tls,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetDNSSEC",
+ SD_BUS_ARGS("s", mode),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_dnssec,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors",
+ SD_BUS_ARGS("as", names),
+ SD_BUS_NO_RESULT,
+ bus_link_method_set_dnssec_negative_trust_anchors,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("Revert",
+ SD_BUS_NO_ARGS,
+ SD_BUS_NO_RESULT,
+ bus_link_method_revert,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+
+ SD_BUS_VTABLE_END
+};
+
+const BusObjectImplementation link_object = {
+ "/org/freedesktop/resolve1/link",
+ "org.freedesktop.resolve1.Link",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({link_vtable, link_object_find}),
+ .node_enumerator = link_node_enumerator,
+};
#include "sd-bus.h"
+#include "bus-util.h"
#include "resolved-link.h"
-extern const sd_bus_vtable link_vtable[];
+extern const BusObjectImplementation link_object;
-int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
char *link_bus_path(const Link *link);
-int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
if (!ns)
return -ENOMEM;
- r = set_put_strdupv(ns, ntas);
+ r = set_put_strdupv(&ns, ntas);
if (r < 0)
return r;
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include "sd-netlink.h"
+
#include "in-addr-util.h"
#include "ratelimit.h"
#include "resolve-util.h"
#include "resolved-dns-scope.h"
#include "resolved-dns-search-domain.h"
#include "resolved-dns-server.h"
-#include "resolved-manager.h"
#define LINK_SEARCH_DOMAINS_MAX 256
#define LINK_DNS_SERVERS_MAX 256
p = h;
r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
- return log_error_errno(r, "Failed to unescape host name: %m");
+ return log_error_errno(r, "Failed to unescape hostname: %m");
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Couldn't find a single label in hostname.");
r = dns_label_escape_new(decoded, r, &n);
if (r < 0)
- return log_error_errno(r, "Failed to escape host name: %m");
+ return log_error_errno(r, "Failed to escape hostname: %m");
if (is_localhost(n))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
p = fallback_hostname();
r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
- return log_error_errno(r, "Failed to unescape fallback host name: %m");
+ return log_error_errno(r, "Failed to unescape fallback hostname: %m");
assert(r > 0); /* The fallback hostname must have at least one label */
int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- union {
- struct cmsghdr header; /* For alignment */
- uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
- + CMSG_SPACE(int) /* ttl/hoplimit */
- + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
+ + CMSG_SPACE(int) /* ttl/hoplimit */
+ + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */) control;
union sockaddr_union sa;
struct iovec iov;
struct msghdr mh = {
iov = IOVEC_MAKE(DNS_PACKET_DATA(p), p->allocated);
- l = recvmsg(fd, &mh, 0);
- if (l < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- return 0;
-
- return -errno;
- }
+ l = recvmsg_safe(fd, &mh, 0);
+ if (IN_SET(l, -EAGAIN, -EINTR))
+ return 0;
+ if (l < 0)
+ return l;
if (l == 0)
return 0;
- assert(!(mh.msg_flags & MSG_CTRUNC));
assert(!(mh.msg_flags & MSG_TRUNC));
p->size = (size_t) l;
uint16_t port,
const struct in_addr *source,
DnsPacket *p) {
- union {
- struct cmsghdr header; /* For alignment */
- uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
- } control = {};
+
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
union sockaddr_union sa;
struct iovec iov;
struct msghdr mh = {
struct in_pktinfo *pi;
mh.msg_control = &control;
- mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
+ mh.msg_controllen = sizeof(control);
cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_len = mh.msg_controllen;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
const struct in6_addr *source,
DnsPacket *p) {
- union {
- struct cmsghdr header; /* For alignment */
- uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in6_pktinfo))) control = {};
union sockaddr_union sa;
struct iovec iov;
struct msghdr mh = {
struct in6_pktinfo *pi;
mh.msg_control = &control;
- mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
+ mh.msg_controllen = sizeof(control);
cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_len = mh.msg_controllen;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <sys/stat.h>
+
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-network.h"
#include "resolved-conf.h"
#include "resolved-dns-query.h"
#include "resolved-dns-search-domain.h"
-#include "resolved-dns-server.h"
#include "resolved-dns-stream.h"
#include "resolved-dns-trust-anchor.h"
-#include "resolved-dnstls.h"
#include "resolved-link.h"
#define MANAGER_SEARCH_DOMAINS_MAX 256
bool need_builtin_fallbacks:1;
bool read_resolv_conf:1;
- usec_t resolv_conf_mtime;
+ struct stat resolv_conf_stat;
DnsTrustAnchor trust_anchor;
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+/* For some reason we need some extra cmsg space on some kernels/archs. One of those days we ned to figure out why */
#define EXTRA_CMSG_SPACE 1024
int manager_is_own_hostname(Manager *m, const char *name);
#include "resolved-conf.h"
#include "resolved-dns-server.h"
#include "resolved-resolv-conf.h"
+#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "tmpfile-util-label.h"
}
/* Have we already seen the file? */
- if (timespec_load(&st.st_mtim) == m->resolv_conf_mtime)
+ if (stat_inode_unmodified(&st, &m->resolv_conf_stat))
return 0;
if (file_is_our_own(&st))
log_syntax(NULL, LOG_DEBUG, "/etc/resolv.conf", n, 0, "Ignoring resolv.conf line: %s", l);
}
- m->resolv_conf_mtime = timespec_load(&st.st_mtim);
+ m->resolv_conf_stat = st;
/* Flush out all servers and search domains that are still
* marked. Those are then ones that didn't appear in the new
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include "alloc-util.h"
-#include "macro.h"
-#include "resolved-util.h"
-#include "socket-netlink.h"
-
-int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
- _cleanup_free_ char *buf = NULL, *name = NULL;
- const char *m;
- int r;
-
- assert(s);
-
- m = strchr(s, '#');
- if (m) {
- name = strdup(m+1);
- if (!name)
- return -ENOMEM;
-
- buf = strndup(s, m - s);
- if (!buf)
- return -ENOMEM;
-
- s = buf;
- }
-
- r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
- if (r < 0)
- return r;
-
- if (server_name)
- *server_name = TAKE_PTR(name);
-
- return r;
-}
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1+ */
-#pragma once
-
-#include "in-addr-util.h"
-
-int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
#include "sd-daemon.h"
#include "sd-event.h"
+#include "bus-log-control-api.h"
#include "capability-util.h"
#include "daemon-util.h"
#include "main-func.h"
#include "mkdir.h"
+#include "resolved-bus.h"
#include "resolved-conf.h"
#include "resolved-manager.h"
#include "resolved-resolv-conf.h"
#include "selinux-util.h"
+#include "service-util.h"
#include "signal-util.h"
#include "user-util.h"
log_setup_service();
- if (argc != 1)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+ r = service_parse_argv("systemd-resolved.service",
+ "Provide name resolution with caching using DNS, mDNS, LLMNR.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
umask(0022);
+++ /dev/null
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include "log.h"
-#include "resolved-util.h"
-#include "string-util.h"
-#include "tests.h"
-
-
-static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
- int family, ifindex;
- union in_addr_union ua;
- _cleanup_free_ char *server_name = NULL;
-
- assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
- assert_se(streq_ptr(server_name, expected));
-}
-
-static void test_in_addr_ifindex_name_from_string_auto(void) {
- log_info("/* %s */", __func__);
-
- test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
- test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
- test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
- test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
-}
-
-int main(int argc, char **argv) {
- test_setup_logging(LOG_DEBUG);
-
- test_in_addr_ifindex_name_from_string_auto();
- return 0;
-}
return r;
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
return r;
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
return log_error_errno(r, "Failed to change unit suffix: %m");
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
uint32_t oem_revision;
char asl_compiler_id[4];
uint32_t asl_compiler_revision;
-};
+} _packed_;
enum {
ACPI_FPDT_TYPE_BOOT = 0,
uint8_t revision;
uint8_t reserved[4];
uint64_t ptr;
-};
+} _packed_;
struct acpi_fpdt_boot_header {
char signature[4];
uint32_t length;
-};
+} _packed_;
enum {
ACPI_FPDT_S3PERF_RESUME_REC = 0,
uint64_t startup_start;
uint64_t exit_services_entry;
uint64_t exit_services_exit;
-};
+} _packed;
int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) {
_cleanup_free_ char *buf = NULL;
pollfd[FD_INOTIFY].events = POLLIN;
for (;;) {
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
char passphrase[LINE_MAX+1];
- struct msghdr msghdr;
struct iovec iovec;
struct ucred *ucred;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control;
ssize_t n;
int k;
usec_t t;
iovec = IOVEC_MAKE(passphrase, sizeof(passphrase));
- zero(control);
- zero(msghdr);
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
- msghdr.msg_control = &control;
- msghdr.msg_controllen = sizeof(control);
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
- n = recvmsg(socket_fd, &msghdr, 0);
+ n = recvmsg_safe(socket_fd, &msghdr, 0);
+ if (IN_SET(n, -EAGAIN, -EINTR))
+ continue;
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
- continue;
-
- r = -errno;
+ r = (int) n;
goto finish;
}
continue;
}
- if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
- control.cmsghdr.cmsg_level != SOL_SOCKET ||
- control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
- control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
+ if (!ucred) {
log_debug("Received message without credentials. Ignoring.");
continue;
}
- ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
if (ucred->uid != 0) {
log_debug("Got request from unprivileged user. Ignoring.");
continue;
--- /dev/null
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+
+#include "binfmt-util.h"
+#include "fileio.h"
+#include "missing_magic.h"
+#include "stat-util.h"
+
+int disable_binfmt(void) {
+ int r;
+
+ /* Flush out all rules. This is important during shutdown to cover for rules using "F", since those
+ * might pin a file and thus block us from unmounting stuff cleanly.
+ *
+ * We are a bit careful here, since binfmt_misc might still be an autofs which we don't want to
+ * trigger. */
+
+ r = path_is_fs_type("/proc/sys/fs/binfmt_misc", BINFMTFS_MAGIC);
+ if (r == 0 || r == -ENOENT) {
+ log_debug("binfmt_misc is not mounted, not detaching entries.");
+ return 0;
+ }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to determine whether binfmt_misc is mounted: %m");
+
+ r = write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to unregister binfmt_misc entries: %m");
+
+ log_debug("Unregistered all remaining binfmt_misc entries.");
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int disable_binfmt(void);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bond-util.h"
+#include "string-table.h"
+
+static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
+ [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
+ [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
+ [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
+ [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
+ [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
+ [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
+ [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
+
+static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
+ [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
+ [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
+ [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
+ [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
+ [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
+
+static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
+ [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
+ [NETDEV_BOND_LACP_RATE_FAST] = "fast",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
+
+static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
+ [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
+ [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
+ [NETDEV_BOND_AD_SELECT_COUNT] = "count",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+
+static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
+ [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
+ [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
+ [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
+
+static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
+ [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
+ [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
+ [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
+ [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
+
+static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
+ [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
+ [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
+
+static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
+ [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
+ [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
+ [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <netinet/in.h>
+#include <linux/if_bonding.h>
+
+#include "macro.h"
+
+/*
+ * Maximum number of targets supported by the kernel for a single
+ * bond netdev.
+ */
+#define NETDEV_BOND_ARP_TARGETS_MAX 16
+
+typedef enum BondMode {
+ NETDEV_BOND_MODE_BALANCE_RR = BOND_MODE_ROUNDROBIN,
+ NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
+ NETDEV_BOND_MODE_BALANCE_XOR = BOND_MODE_XOR,
+ NETDEV_BOND_MODE_BROADCAST = BOND_MODE_BROADCAST,
+ NETDEV_BOND_MODE_802_3AD = BOND_MODE_8023AD,
+ NETDEV_BOND_MODE_BALANCE_TLB = BOND_MODE_TLB,
+ NETDEV_BOND_MODE_BALANCE_ALB = BOND_MODE_ALB,
+ _NETDEV_BOND_MODE_MAX,
+ _NETDEV_BOND_MODE_INVALID = -1
+} BondMode;
+
+typedef enum BondXmitHashPolicy {
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER2 = BOND_XMIT_POLICY_LAYER2,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER34 = BOND_XMIT_POLICY_LAYER34,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER23 = BOND_XMIT_POLICY_LAYER23,
+ NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23 = BOND_XMIT_POLICY_ENCAP23,
+ NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34 = BOND_XMIT_POLICY_ENCAP34,
+ _NETDEV_BOND_XMIT_HASH_POLICY_MAX,
+ _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
+} BondXmitHashPolicy;
+
+typedef enum BondLacpRate {
+ NETDEV_BOND_LACP_RATE_SLOW,
+ NETDEV_BOND_LACP_RATE_FAST,
+ _NETDEV_BOND_LACP_RATE_MAX,
+ _NETDEV_BOND_LACP_RATE_INVALID = -1,
+} BondLacpRate;
+
+typedef enum BondAdSelect {
+ NETDEV_BOND_AD_SELECT_STABLE,
+ NETDEV_BOND_AD_SELECT_BANDWIDTH,
+ NETDEV_BOND_AD_SELECT_COUNT,
+ _NETDEV_BOND_AD_SELECT_MAX,
+ _NETDEV_BOND_AD_SELECT_INVALID = -1,
+} BondAdSelect;
+
+typedef enum BondFailOverMac {
+ NETDEV_BOND_FAIL_OVER_MAC_NONE,
+ NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
+ NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
+ _NETDEV_BOND_FAIL_OVER_MAC_MAX,
+ _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
+} BondFailOverMac;
+
+typedef enum BondArpValidate {
+ NETDEV_BOND_ARP_VALIDATE_NONE,
+ NETDEV_BOND_ARP_VALIDATE_ACTIVE,
+ NETDEV_BOND_ARP_VALIDATE_BACKUP,
+ NETDEV_BOND_ARP_VALIDATE_ALL,
+ _NETDEV_BOND_ARP_VALIDATE_MAX,
+ _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
+} BondArpValidate;
+
+typedef enum BondArpAllTargets {
+ NETDEV_BOND_ARP_ALL_TARGETS_ANY,
+ NETDEV_BOND_ARP_ALL_TARGETS_ALL,
+ _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
+ _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
+} BondArpAllTargets;
+
+typedef enum BondPrimaryReselect {
+ NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
+ NETDEV_BOND_PRIMARY_RESELECT_BETTER,
+ NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
+ _NETDEV_BOND_PRIMARY_RESELECT_MAX,
+ _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
+} BondPrimaryReselect;
+
+const char *bond_mode_to_string(BondMode d) _const_;
+BondMode bond_mode_from_string(const char *d) _pure_;
+
+const char *bond_xmit_hash_policy_to_string(BondXmitHashPolicy d) _const_;
+BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
+
+const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
+BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
+
+const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
+BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
+
+const char *bond_ad_select_to_string(BondAdSelect d) _const_;
+BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
+
+const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
+BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
+
+const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
+BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
+
+const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
+BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-locator.h"
+
+const BusLocator* const bus_home_mgr = &(BusLocator){
+ .destination = "org.freedesktop.home1",
+ .path = "/org/freedesktop/home1",
+ .interface = "org.freedesktop.home1.Manager",
+};
+
+const BusLocator* const bus_import_mgr = &(BusLocator){
+ .destination ="org.freedesktop.import1",
+ .path = "/org/freedesktop/import1",
+ .interface = "org.freedesktop.import1.Manager"
+};
+
+const BusLocator* const bus_locale = &(BusLocator){
+ .destination = "org.freedesktop.locale1",
+ .path = "/org/freedesktop/locale1",
+ .interface = "org.freedesktop.locale1"
+};
+
+const BusLocator* const bus_login_mgr = &(BusLocator){
+ .destination = "org.freedesktop.login1",
+ .path = "/org/freedesktop/login1",
+ .interface = "org.freedesktop.login1.Manager"
+};
+
+const BusLocator* const bus_machine_mgr = &(BusLocator){
+ .destination ="org.freedesktop.machine1",
+ .path = "/org/freedesktop/machine1",
+ .interface = "org.freedesktop.machine1.Manager"
+};
+
+const BusLocator* const bus_network_mgr = &(BusLocator){
+ .destination = "org.freedesktop.network1",
+ .path = "/org/freedesktop/network1",
+ .interface = "org.freedesktop.network1.Manager"
+};
+
+const BusLocator* const bus_portable_mgr = &(BusLocator){
+ .destination = "org.freedesktop.portable1",
+ .path = "/org/freedesktop/portable1",
+ .interface = "org.freedesktop.portable1.Manager"
+};
+
+const BusLocator* const bus_resolve_mgr = &(BusLocator){
+ .destination = "org.freedesktop.resolve1",
+ .path = "/org/freedesktop/resolve1",
+ .interface = "org.freedesktop.resolve1.Manager"
+};
+
+const BusLocator* const bus_systemd_mgr = &(BusLocator){
+ .destination = "org.freedesktop.systemd1",
+ .path = "/org/freedesktop/systemd1",
+ .interface = "org.freedesktop.systemd1.Manager"
+};
+
+const BusLocator* const bus_timedate = &(BusLocator){
+ .destination = "org.freedesktop.timedate1",
+ .path = "/org/freedesktop/timedate1",
+ .interface = "org.freedesktop.timedate1"
+};
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+typedef struct BusLocator {
+ const char *destination;
+ const char *path;
+ const char *interface;
+} BusLocator;
+
+extern const BusLocator* const bus_home_mgr;
+extern const BusLocator* const bus_import_mgr;
+extern const BusLocator* const bus_locale;
+extern const BusLocator* const bus_login_mgr;
+extern const BusLocator* const bus_machine_mgr;
+extern const BusLocator* const bus_network_mgr;
+extern const BusLocator* const bus_portable_mgr;
+extern const BusLocator* const bus_resolve_mgr;
+extern const BusLocator* const bus_systemd_mgr;
+extern const BusLocator* const bus_timedate;
SD_BUS_VTABLE_END,
};
-int bus_log_control_api_register(sd_bus *bus) {
- int r;
-
- r = sd_bus_add_object_vtable(
- bus,
- NULL,
- "/org/freedesktop/LogControl1",
- "org.freedesktop.LogControl1",
- log_control_vtable, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to register service API object: %m");
-
- return 0;
-}
+const BusObjectImplementation log_control_object = {
+ "/org/freedesktop/LogControl1",
+ "org.freedesktop.LogControl1",
+ .vtables = BUS_VTABLES(log_control_vtable),
+};
#include "sd-bus.h"
-int bus_log_control_api_register(sd_bus *bus);
+#include "bus-util.h"
+
+extern const BusObjectImplementation log_control_object;
+static inline int bus_log_control_api_register(sd_bus *bus) {
+ return bus_add_implementation(bus, &log_control_object, NULL);
+}
int bus_property_get_log_level(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
int bus_property_set_log_level(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error);
if (STR_IN_SET(field, "SloppyOptions",
"LazyUnmount",
- "ForceUnmount"))
+ "ForceUnmount",
+ "ReadwriteOnly"))
return bus_append_parse_boolean(m, field, eq);
return 0;
#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-introspect.h"
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
return sd_bus_message_new_method_call(bus, m, locator->destination, locator->path, locator->interface, member);
}
+
+int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata) {
+ int r;
+
+ log_debug("Registering bus object implementation for path=%s iface=%s", impl->path, impl->interface);
+
+ for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
+ r = sd_bus_add_object_vtable(bus, NULL,
+ impl->path,
+ impl->interface,
+ *p,
+ userdata);
+ if (r < 0)
+ return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
+ impl->path,
+ impl->interface);
+ }
+
+ for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
+ r = sd_bus_add_fallback_vtable(bus, NULL,
+ impl->path,
+ impl->interface,
+ p->vtable,
+ p->object_find,
+ userdata);
+ if (r < 0)
+ return log_error_errno(r, "Failed to register bus path %s with interface %s: %m",
+ impl->path,
+ impl->interface);
+ }
+
+ if (impl->node_enumerator) {
+ r = sd_bus_add_node_enumerator(bus, NULL,
+ impl->path,
+ impl->node_enumerator,
+ userdata);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add node enumerator for %s: %m",
+ impl->path);
+ }
+
+ for (size_t i = 0; impl->children && impl->children[i]; i++) {
+ r = bus_add_implementation(bus, impl->children[i], userdata);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static const BusObjectImplementation* find_implementation(
+ const char *pattern,
+ const BusObjectImplementation* const* bus_objects) {
+
+ for (size_t i = 0; bus_objects && bus_objects[i]; i++) {
+ const BusObjectImplementation *impl = bus_objects[i];
+
+ if (STR_IN_SET(pattern, impl->path, impl->interface))
+ return impl;
+
+ impl = find_implementation(pattern, impl->children);
+ if (impl)
+ return impl;
+ }
+
+ return NULL;
+}
+
+static int bus_introspect_implementation(
+ struct introspect *intro,
+ const BusObjectImplementation *impl) {
+ int r;
+
+ for (const sd_bus_vtable **p = impl->vtables; p && *p; p++) {
+ r = introspect_write_interface(intro, impl->interface, *p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write introspection data: %m");
+ }
+
+ for (const BusObjectVtablePair *p = impl->fallback_vtables; p && p->vtable; p++) {
+ r = introspect_write_interface(intro, impl->interface, p->vtable);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write introspection data: %m");
+ }
+
+ return 0;
+}
+
+static void list_paths(
+ FILE *out,
+ const BusObjectImplementation* const* bus_objects) {
+
+ for (size_t i = 0; bus_objects[i]; i++) {
+ fprintf(out, "%s\t%s\n", bus_objects[i]->path, bus_objects[i]->interface);
+ if (bus_objects[i]->children)
+ list_paths(out, bus_objects[i]->children);
+ }
+}
+
+int bus_introspect_implementations(
+ FILE *out,
+ const char *pattern,
+ const BusObjectImplementation* const* bus_objects) {
+
+ const BusObjectImplementation *impl, *main_impl = NULL;
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ if (streq(pattern, "list")) {
+ list_paths(out, bus_objects);
+ return 0;
+ }
+
+ struct introspect intro = {};
+ bool is_interface = interface_name_is_valid(pattern);
+
+ impl = find_implementation(pattern, bus_objects);
+ if (!impl)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+ "%s %s not found",
+ is_interface ? "Interface" : "Object path",
+ pattern);
+
+ /* We use trusted=false here to get all the @org.freedesktop.systemd1.Privileged annotations. */
+ r = introspect_begin(&intro, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write introspection data: %m");
+
+ r = introspect_write_default_interfaces(&intro, impl->manager);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write introspection data: %m");
+
+ /* Check if there is a non-fallback path that applies to the given interface, also
+ * print it. This is useful in the case of units: o.fd.systemd1.Service is declared
+ * as a fallback vtable for o/fd/systemd1/unit, and we also want to print
+ * o.fd.systemd1.Unit, which is the non-fallback implementation. */
+ if (impl->fallback_vtables && is_interface)
+ main_impl = find_implementation(impl->path, bus_objects);
+
+ if (main_impl)
+ bus_introspect_implementation(&intro, main_impl);
+
+ if (impl != main_impl)
+ bus_introspect_implementation(&intro, impl);
+
+ _cleanup_set_free_ Set *nodes = NULL;
+
+ for (size_t i = 0; impl->children && impl->children[i]; i++) {
+ r = set_put_strdup(&nodes, impl->children[i]->path);
+ if (r < 0)
+ return log_oom();
+ }
+
+ r = introspect_write_child_nodes(&intro, nodes, impl->path);
+ if (r < 0)
+ return r;
+
+ r = introspect_finish(&intro, &s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write introspection data: %m");
+
+ fputs(s, out);
+ return 0;
+}
#include "sd-bus.h"
#include "sd-event.h"
+#include "bus-locator.h"
#include "macro.h"
#include "set.h"
#include "string-util.h"
_BUS_TRANSPORT_INVALID = -1
} BusTransport;
-typedef struct BusLocator {
- const char *destination;
- const char *path;
- const char *interface;
-} BusLocator;
+typedef struct BusObjectImplementation BusObjectImplementation;
+
+typedef struct BusObjectVtablePair {
+ const sd_bus_vtable *vtable;
+ sd_bus_object_find_t object_find;
+} BusObjectVtablePair;
+
+struct BusObjectImplementation {
+ const char *path;
+ const char *interface;
+ const sd_bus_vtable **vtables;
+ const BusObjectVtablePair *fallback_vtables;
+ sd_bus_node_enumerator_t node_enumerator;
+ bool manager;
+ const BusObjectImplementation **children;
+};
+
+#define BUS_VTABLES(...) ((const sd_bus_vtable* []){ __VA_ARGS__, NULL })
+#define BUS_FALLBACK_VTABLES(...) ((const BusObjectVtablePair[]) { __VA_ARGS__, {} })
+#define BUS_IMPLEMENTATIONS(...) ((const BusObjectImplementation* []) { __VA_ARGS__, NULL })
typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
int bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const BusLocator *locator, const char *member, sd_bus_message_handler_t callback, void *userdata);
int bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const BusLocator *locator, const char *member, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata);
int bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const BusLocator *locator, const char *member);
+
+int bus_add_implementation(sd_bus *bus, const BusObjectImplementation *impl, void *userdata);
+int bus_introspect_implementations(
+ FILE *out,
+ const char *pattern,
+ const BusObjectImplementation* const* bus_objects);
if (!d)
return;
- set_free_free(d->jobs);
+ set_free(d->jobs);
sd_bus_slot_unref(d->slot_disconnected);
sd_bus_slot_unref(d->slot_job_removed);
}
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
- int r;
-
assert(d);
- r = set_ensure_allocated(&d->jobs, &string_hash_ops);
- if (r < 0)
- return r;
-
- return set_put_strdup(d->jobs, path);
+ return set_put_strdup(&d->jobs, path);
}
int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
DEFINE_TRIVIAL_CLEANUP_FUNC(WaitForItem*, wait_for_item_free);
+static void call_unit_callback_and_wait(BusWaitForUnits *d, WaitForItem *item, bool good) {
+ d->current = item;
+
+ if (item->unit_callback)
+ item->unit_callback(d, item->bus_path, good, item->userdata);
+
+ wait_for_item_free(item);
+}
+
static void bus_wait_for_units_clear(BusWaitForUnits *d) {
WaitForItem *item;
d->slot_disconnected = sd_bus_slot_unref(d->slot_disconnected);
d->bus = sd_bus_unref(d->bus);
- while ((item = hashmap_first(d->items))) {
- d->current = item;
-
- item->unit_callback(d, item->bus_path, false, item->userdata);
- wait_for_item_free(item);
- }
+ while ((item = hashmap_first(d->items)))
+ call_unit_callback_and_wait(d, item, false);
d->items = hashmap_free(d->items);
}
return;
}
- if (item->unit_callback) {
- d->current = item;
- item->unit_callback(d, item->bus_path, true, item->userdata);
- }
-
- wait_for_item_free(item);
-
+ call_unit_callback_and_wait(d, item, true);
bus_wait_for_units_check_ready(d);
}
log_debug_errno(sd_bus_error_get_errno(error), "GetAll() failed for %s: %s",
item->bus_path, error->message);
- d->current = item;
- item->unit_callback(d, item->bus_path, false, item->userdata);
- wait_for_item_free(item);
-
+ call_unit_callback_and_wait(d, item, false);
bus_wait_for_units_check_ready(d);
return 0;
}
#include "process-util.h"
#include "sort-util.h"
#include "string-util.h"
+#include "strv.h"
#include "time-util.h"
#define BITS_WEEKDAYS 127
* linked compenents anyway. */
#define CALENDARSPEC_COMPONENTS_MAX 240
+/* Let's make sure that the microsecond component is safe to be stored in an 'int' */
+assert_cc(INT_MAX >= USEC_PER_SEC);
+
static void chain_free(CalendarComponent *c) {
CalendarComponent *n;
if (i->stop > i->start && i->repeat > 0)
i->stop -= (i->stop - i->start) % i->repeat;
+ /* If a repeat value is specified, but it cannot even be triggered once, let's suppress
+ * it.
+ *
+ * Similar, if the stop value is the same as the start value, then let's just make this a
+ * non-repeating chain element */
+ if ((i->stop > i->start && i->repeat > 0 && i->start + i->repeat > i->stop) ||
+ i->start == i->stop) {
+ i->repeat = 0;
+ i->stop = -1;
+ }
}
if (n <= 1)
return 0;
}
-_pure_ static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) {
+static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) {
assert(to >= from);
if (!c)
}
r = fflush_and_check(f);
+ fclose(f);
+
if (r < 0) {
free(buf);
- fclose(f);
return r;
}
- fclose(f);
-
*p = buf;
return 0;
}
if (repeat == 0)
return -ERANGE;
+ } else {
+ /* If no repeat value is specified for the µs component, then let's explicitly refuse ranges
+ * below 1s because our default repeat granularity is beyond that. */
+
+ /* Overflow check */
+ if (start > INT_MAX - repeat)
+ return -ERANGE;
+
+ if (usec && stop >= 0 && start + repeat > stop)
+ return -EINVAL;
}
if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':'))
if (r < 0)
return r;
- } else if (strcaseeq(p, "annually") ||
- strcaseeq(p, "yearly") ||
- strcaseeq(p, "anually") /* backwards compatibility */ ) {
+ } else if (STRCASE_IN_SET(p,
+ "annually",
+ "yearly",
+ "anually") /* backwards compatibility */ ) {
r = const_chain(1, &c->month);
if (r < 0)
if (r < 0)
return r;
- } else if (strcaseeq(p, "biannually") ||
- strcaseeq(p, "bi-annually") ||
- strcaseeq(p, "semiannually") ||
- strcaseeq(p, "semi-annually")) {
+ } else if (STRCASE_IN_SET(p,
+ "biannually",
+ "bi-annually",
+ "semiannually",
+ "semi-annually")) {
r = const_chain(1, &c->month);
if (r < 0)
typedef struct CalendarSpec {
int weekdays_bits;
- bool end_of_month;
- bool utc;
- int dst;
+ bool end_of_month:1;
+ bool utc:1;
+ signed int dst:2;
char *timezone;
CalendarComponent *year;
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "glob-util.h"
#include "hostname-util.h"
#include "ima-util.h"
return c;
}
-void condition_free(Condition *c) {
+Condition* condition_free(Condition *c) {
assert(c);
free(c->parameter);
- free(c);
+ return mfree(c);
}
Condition* condition_free_list_type(Condition *head, ConditionType type) {
return head;
}
-static int condition_test_kernel_command_line(Condition *c) {
+static int condition_test_kernel_command_line(Condition *c, char **env) {
_cleanup_free_ char *line = NULL;
const char *p;
bool equal;
}
}
-static int condition_test_kernel_version(Condition *c) {
+static int condition_test_kernel_version(Condition *c, char **env) {
OrderOperator order;
struct utsname u;
const char *p;
return true;
}
-static int condition_test_memory(Condition *c) {
+static int condition_test_memory(Condition *c, char **env) {
OrderOperator order;
uint64_t m, k;
const char *p;
return test_order(CMP(m, k), order);
}
-static int condition_test_cpus(Condition *c) {
+static int condition_test_cpus(Condition *c, char **env) {
OrderOperator order;
const char *p;
unsigned k;
return test_order(CMP((unsigned) n, k), order);
}
-static int condition_test_user(Condition *c) {
+static int condition_test_user(Condition *c, char **env) {
uid_t id;
int r;
_cleanup_free_ char *username = NULL;
return id == getuid() || id == geteuid();
}
-static int condition_test_control_group_controller(Condition *c) {
+static int condition_test_control_group_controller(Condition *c, char **env) {
int r;
CGroupMask system_mask, wanted_mask = 0;
return FLAGS_SET(system_mask, wanted_mask);
}
-static int condition_test_group(Condition *c) {
+static int condition_test_group(Condition *c, char **env) {
gid_t id;
int r;
return in_group(c->parameter) > 0;
}
-static int condition_test_virtualization(Condition *c) {
+static int condition_test_virtualization(Condition *c, char **env) {
int b, v;
assert(c);
return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
}
-static int condition_test_architecture(Condition *c) {
+static int condition_test_architecture(Condition *c, char **env) {
int a, b;
assert(c);
return a == b;
}
-static int condition_test_host(Condition *c) {
+static int condition_test_host(Condition *c, char **env) {
_cleanup_free_ char *h = NULL;
sd_id128_t x, y;
int r;
return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
}
-static int condition_test_ac_power(Condition *c) {
+static int condition_test_ac_power(Condition *c, char **env) {
int r;
assert(c);
return (on_ac_power() != 0) == !!r;
}
-static int condition_test_security(Condition *c) {
+static int condition_test_security(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_SECURITY);
return false;
}
-static int condition_test_capability(Condition *c) {
+static int condition_test_capability(Condition *c, char **env) {
unsigned long long capabilities = (unsigned long long) -1;
_cleanup_fclose_ FILE *f = NULL;
int value, r;
return !!(capabilities & (1ULL << value));
}
-static int condition_test_needs_update(Condition *c) {
- const char *p;
+static int condition_test_needs_update(Condition *c, char **env) {
struct stat usr, other;
+ const char *p;
+ bool b;
+ int r;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_NEEDS_UPDATE);
+ r = proc_cmdline_get_bool("systemd.condition-needs-update", &b);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-needs-update= kernel command line argument, ignoring: %m");
+ if (r > 0)
+ return b;
+
+ if (!path_is_absolute(c->parameter)) {
+ log_debug("Specified condition parameter '%s' is not absolute, assuming an update is needed.", c->parameter);
+ return true;
+ }
+
/* If the file system is read-only we shouldn't suggest an update */
- if (path_is_read_only_fs(c->parameter) > 0)
+ r = path_is_read_only_fs(c->parameter);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine if '%s' is read-only, ignoring: %m", c->parameter);
+ if (r > 0)
return false;
- /* Any other failure means we should allow the condition to be true,
- * so that we rather invoke too many update tools than too
- * few. */
-
- if (!path_is_absolute(c->parameter))
- return true;
+ /* Any other failure means we should allow the condition to be true, so that we rather invoke too
+ * many update tools than too few. */
p = strjoina(c->parameter, "/.updated");
- if (lstat(p, &other) < 0)
+ if (lstat(p, &other) < 0) {
+ if (errno != ENOENT)
+ log_debug_errno(errno, "Failed to stat() '%s', assuming an update is needed: %m", p);
return true;
+ }
- if (lstat("/usr/", &usr) < 0)
+ if (lstat("/usr/", &usr) < 0) {
+ log_debug_errno(errno, "Failed to stat() /usr/, assuming an update is needed: %m");
return true;
+ }
/*
* First, compare seconds as they are always accurate...
* AND the target file's nanoseconds == 0
* (otherwise the filesystem supports nsec timestamps, see stat(2)).
*/
- if (usr.st_mtim.tv_nsec > 0 && other.st_mtim.tv_nsec == 0) {
- _cleanup_free_ char *timestamp_str = NULL;
- uint64_t timestamp;
- int r;
+ if (usr.st_mtim.tv_nsec == 0 || other.st_mtim.tv_nsec > 0)
+ return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
- r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
- if (r < 0) {
- log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
- return true;
- } else if (r == 0) {
- log_debug("No data in timestamp file '%s', using mtime", p);
- return true;
- }
-
- r = safe_atou64(timestamp_str, ×tamp);
- if (r < 0) {
- log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
- return true;
- }
+ _cleanup_free_ char *timestamp_str = NULL;
+ r = parse_env_file(NULL, p, "TIMESTAMP_NSEC", ×tamp_str);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
+ return true;
+ } else if (r == 0) {
+ log_debug("No data in timestamp file '%s', using mtime.", p);
+ return true;
+ }
- timespec_store(&other.st_mtim, timestamp);
+ uint64_t timestamp;
+ r = safe_atou64(timestamp_str, ×tamp);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p);
+ return true;
}
- return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec;
+ return timespec_load_nsec(&usr.st_mtim) > timestamp;
}
-static int condition_test_first_boot(Condition *c) {
- int r;
+static int condition_test_first_boot(Condition *c, char **env) {
+ int r, q;
+ bool b;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_FIRST_BOOT);
+ r = proc_cmdline_get_bool("systemd.condition-first-boot", &b);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse systemd.condition-first-boot= kernel command line argument, ignoring: %m");
+ if (r > 0)
+ return b == !!r;
+
r = parse_boolean(c->parameter);
if (r < 0)
return r;
- return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
+ q = access("/run/systemd/first-boot", F_OK);
+ if (q < 0 && errno != ENOENT)
+ log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, ignoring: %m");
+
+ return (q >= 0) == !!r;
+}
+
+static int condition_test_environment(Condition *c, char **env) {
+ bool equal;
+ char **i;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_ENVIRONMENT);
+
+ equal = strchr(c->parameter, '=');
+
+ STRV_FOREACH(i, env) {
+ bool found;
+
+ if (equal)
+ found = streq(c->parameter, *i);
+ else {
+ const char *f;
+
+ f = startswith(*i, c->parameter);
+ found = f && IN_SET(*f, 0, '=');
+ }
+
+ if (found)
+ return true;
+ }
+
+ return false;
}
-static int condition_test_path_exists(Condition *c) {
+static int condition_test_path_exists(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_EXISTS);
return access(c->parameter, F_OK) >= 0;
}
-static int condition_test_path_exists_glob(Condition *c) {
+static int condition_test_path_exists_glob(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_EXISTS_GLOB);
return glob_exists(c->parameter) > 0;
}
-static int condition_test_path_is_directory(Condition *c) {
+static int condition_test_path_is_directory(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_DIRECTORY);
return is_dir(c->parameter, true) > 0;
}
-static int condition_test_path_is_symbolic_link(Condition *c) {
+static int condition_test_path_is_symbolic_link(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
return is_symlink(c->parameter) > 0;
}
-static int condition_test_path_is_mount_point(Condition *c) {
+static int condition_test_path_is_mount_point(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
return path_is_mount_point(c->parameter, NULL, AT_SYMLINK_FOLLOW) > 0;
}
-static int condition_test_path_is_read_write(Condition *c) {
+static int condition_test_path_is_read_write(Condition *c, char **env) {
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_READ_WRITE);
return path_is_read_only_fs(c->parameter) <= 0;
}
-static int condition_test_directory_not_empty(Condition *c) {
+static int condition_test_path_is_encrypted(Condition *c, char **env) {
+ int r;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_IS_ENCRYPTED);
+
+ r = path_is_encrypted(c->parameter);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to determine if '%s' is encrypted: %m", c->parameter);
+
+ return r > 0;
+}
+
+static int condition_test_directory_not_empty(Condition *c, char **env) {
int r;
assert(c);
return r <= 0 && r != -ENOENT;
}
-static int condition_test_file_not_empty(Condition *c) {
+static int condition_test_file_not_empty(Condition *c, char **env) {
struct stat st;
assert(c);
st.st_size > 0);
}
-static int condition_test_file_is_executable(Condition *c) {
+static int condition_test_file_is_executable(Condition *c, char **env) {
struct stat st;
assert(c);
(st.st_mode & 0111));
}
-static int condition_test_null(Condition *c) {
+static int condition_test_null(Condition *c, char **env) {
assert(c);
assert(c->type == CONDITION_NULL);
return true;
}
-int condition_test(Condition *c) {
+int condition_test(Condition *c, char **env) {
- static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
+ static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c, char **env) = {
[CONDITION_PATH_EXISTS] = condition_test_path_exists,
[CONDITION_PATH_EXISTS_GLOB] = condition_test_path_exists_glob,
[CONDITION_PATH_IS_DIRECTORY] = condition_test_path_is_directory,
[CONDITION_PATH_IS_SYMBOLIC_LINK] = condition_test_path_is_symbolic_link,
[CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
[CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
+ [CONDITION_PATH_IS_ENCRYPTED] = condition_test_path_is_encrypted,
[CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
[CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
[CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
[CONDITION_NULL] = condition_test_null,
[CONDITION_CPUS] = condition_test_cpus,
[CONDITION_MEMORY] = condition_test_memory,
+ [CONDITION_ENVIRONMENT] = condition_test_environment,
};
int r, b;
assert(c->type >= 0);
assert(c->type < _CONDITION_TYPE_MAX);
- r = condition_tests[c->type](c);
+ r = condition_tests[c->type](c, env);
if (r < 0) {
c->result = CONDITION_ERROR;
return r;
return b;
}
-bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata) {
+bool condition_test_list(
+ Condition *first,
+ char **env,
+ condition_to_string_t to_string,
+ condition_test_logger_t logger,
+ void *userdata) {
+
Condition *c;
int triggered = -1;
LIST_FOREACH(conditions, c, first) {
int r;
- r = condition_test(c);
+ r = condition_test(c, env);
if (logger) {
const char *p = c->type == CONDITION_NULL ? "true" : c->parameter;
return triggered != 0;
}
-void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
+void condition_dump(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string) {
assert(c);
assert(f);
+ assert(to_string);
prefix = strempty(prefix);
condition_result_to_string(c->result));
}
-void condition_dump_list(Condition *first, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
+void condition_dump_list(Condition *first, FILE *f, const char *prefix, condition_to_string_t to_string) {
Condition *c;
LIST_FOREACH(conditions, c, first)
[CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
[CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
[CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
+ [CONDITION_PATH_IS_ENCRYPTED] = "ConditionPathIsEncrypted",
[CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
[CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
[CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
[CONDITION_NULL] = "ConditionNull",
[CONDITION_CPUS] = "ConditionCPUs",
[CONDITION_MEMORY] = "ConditionMemory",
+ [CONDITION_ENVIRONMENT] = "ConditionEnvironment",
};
DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
[CONDITION_PATH_IS_SYMBOLIC_LINK] = "AssertPathIsSymbolicLink",
[CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
[CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
+ [CONDITION_PATH_IS_ENCRYPTED] = "AssertPathIsEncrypted",
[CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
[CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
[CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
[CONDITION_NULL] = "AssertNull",
[CONDITION_CPUS] = "AssertCPUs",
[CONDITION_MEMORY] = "AssertMemory",
+ [CONDITION_ENVIRONMENT] = "AssertEnvironment",
};
DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
CONDITION_AC_POWER,
CONDITION_MEMORY,
CONDITION_CPUS,
+ CONDITION_ENVIRONMENT,
CONDITION_NEEDS_UPDATE,
CONDITION_FIRST_BOOT,
CONDITION_PATH_IS_SYMBOLIC_LINK,
CONDITION_PATH_IS_MOUNT_POINT,
CONDITION_PATH_IS_READ_WRITE,
+ CONDITION_PATH_IS_ENCRYPTED,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_FILE_NOT_EMPTY,
CONDITION_FILE_IS_EXECUTABLE,
} Condition;
Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate);
-void condition_free(Condition *c);
+Condition* condition_free(Condition *c);
Condition* condition_free_list_type(Condition *first, ConditionType type);
static inline Condition* condition_free_list(Condition *first) {
return condition_free_list_type(first, _CONDITION_TYPE_INVALID);
}
-int condition_test(Condition *c);
+int condition_test(Condition *c, char **env);
+
typedef int (*condition_test_logger_t)(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
-bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata);
+typedef const char* (*condition_to_string_t)(ConditionType t) _const_;
+bool condition_test_list(Condition *first, char **env, condition_to_string_t to_string, condition_test_logger_t logger, void *userdata);
-void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
-void condition_dump_list(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
+void condition_dump(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string);
+void condition_dump_list(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string);
const char* condition_type_to_string(ConditionType t) _const_;
ConditionType condition_type_from_string(const char *s) _pure_;
CONDITION_PATH_IS_SYMBOLIC_LINK,
CONDITION_PATH_IS_MOUNT_POINT,
CONDITION_PATH_IS_READ_WRITE,
+ CONDITION_PATH_IS_ENCRYPTED,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_FILE_NOT_EMPTY,
CONDITION_FILE_IS_EXECUTABLE,
return 0;
}
+
+int config_parse_vlanprotocol(const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ int *vlan_protocol = data;
+ assert(filename);
+ assert(lvalue);
+
+ if (isempty(rvalue)) {
+ *vlan_protocol = -1;
+ return 0;
+ }
+
+ if (STR_IN_SET(rvalue, "802.1ad", "802.1AD"))
+ *vlan_protocol = ETH_P_8021AD;
+ else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
+ *vlan_protocol = ETH_P_8021Q;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
CONFIG_PARSER_PROTOTYPE(config_parse_ip_port);
CONFIG_PARSER_PROTOTYPE(config_parse_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_rlimit);
+CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol);
typedef enum Disabled {
DISABLED_CONFIGURATION,
log_debug("No type detected on partition %s", node);
goto not_found;
}
- if (r == -2) {
- log_debug("Results ambiguous for partition %s", node);
- return -EUCLEAN;
- }
+ if (r == -2)
+ return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
+ "Results ambiguous for partition %s", node);
if (r != 0)
return errno_or_else(EIO);
speed = ethtool_cmd_speed(&ecmd);
*ret_speed = speed == (uint32_t) SPEED_UNKNOWN ?
- SIZE_MAX : (size_t) speed * 1000 * 1000;
+ UINT64_MAX : (uint64_t) speed * 1000 * 1000;
}
if (ret_duplex)
if (epaddr.addr.size != 6)
return -EOPNOTSUPP;
+#pragma GCC diagnostic push
+#if HAVE_ZERO_LENGTH_BOUNDS
+# pragma GCC diagnostic ignored "-Wzero-length-bounds"
+#endif
for (size_t i = 0; i < epaddr.addr.size; i++)
ret->ether_addr_octet[i] = epaddr.addr.data[i];
+#pragma GCC diagnostic pop
return 0;
}
if (r < 0)
return -errno;
- if (ring->rx_pending_set) {
- if (ecmd.rx_pending != ring->rx_pending) {
- ecmd.rx_pending = ring->rx_pending;
- need_update = true;
- }
+ if (ring->rx_pending_set && ecmd.rx_pending != ring->rx_pending) {
+ ecmd.rx_pending = ring->rx_pending;
+ need_update = true;
}
- if (ring->tx_pending_set) {
- if (ecmd.tx_pending != ring->tx_pending) {
- ecmd.tx_pending = ring->tx_pending;
- need_update = true;
- }
+ if (ring->rx_mini_pending_set && ecmd.rx_mini_pending != ring->rx_mini_pending) {
+ ecmd.rx_mini_pending = ring->rx_mini_pending;
+ need_update = true;
+ }
+
+ if (ring->rx_jumbo_pending_set && ecmd.rx_jumbo_pending != ring->rx_jumbo_pending) {
+ ecmd.rx_jumbo_pending = ring->rx_jumbo_pending;
+ need_update = true;
+ }
+
+ if (ring->tx_pending_set && ecmd.tx_pending != ring->tx_pending) {
+ ecmd.tx_pending = ring->tx_pending;
+ need_update = true;
}
if (need_update) {
if (!buffer.info.sset_mask)
return -EINVAL;
+#pragma GCC diagnostic push
+#if HAVE_ZERO_LENGTH_BOUNDS
+# pragma GCC diagnostic ignored "-Wzero-length-bounds"
+#endif
len = buffer.info.data[0];
+#pragma GCC diagnostic pop
strings = malloc0(sizeof(struct ethtool_gstrings) + len * ETH_GSTRING_LEN);
if (!strings)
if (streq(lvalue, "RxBufferSize")) {
ring->rx_pending = k;
ring->rx_pending_set = true;
+ } else if (streq(lvalue, "RxMiniBufferSize")) {
+ ring->rx_mini_pending = k;
+ ring->rx_mini_pending_set = true;
+ } else if (streq(lvalue, "RxJumboBufferSize")) {
+ ring->rx_jumbo_pending = k;
+ ring->rx_jumbo_pending_set = true;
} else if (streq(lvalue, "TxBufferSize")) {
ring->tx_pending = k;
ring->tx_pending_set = true;
typedef struct netdev_ring_param {
uint32_t rx_pending;
+ uint32_t rx_mini_pending;
+ uint32_t rx_jumbo_pending;
uint32_t tx_pending;
bool rx_pending_set;
+ bool rx_mini_pending_set;
+ bool rx_jumbo_pending_set;
bool tx_pending_set;
} netdev_ring_param;
bool uppercase; /* Uppercase string on display */
const char *color; /* ANSI color string to use for this cell. When written to terminal should not move cursor. Will automatically be reset after the cell */
+ const char *rgap_color; /* The ANSI color to use for the gap right of this cell. Usually used to underline entire rows in a gapless fashion */
char *url; /* A URL to use for a clickable hyperlink */
char *formatted; /* A cached textual representation of the cell data, before ellipsation/alignment */
return false;
/* If a color/url/uppercase flag is set, refuse to merge */
- if (d->color)
+ if (d->color || d->rgap_color)
return false;
if (d->url)
return false;
return -ENOMEM;
nd->color = od->color;
+ nd->rgap_color = od->rgap_color;
nd->url = TAKE_PTR(curl);
nd->uppercase = od->uppercase;
return 0;
}
+int table_set_rgap_color(Table *t, TableCell *cell, const char *color) {
+ int r;
+
+ assert(t);
+ assert(cell);
+
+ r = table_dedup_cell(t, cell);
+ if (r < 0)
+ return r;
+
+ table_get_data(t, cell)->rgap_color = empty_to_null(color);
+ return 0;
+}
+
int table_set_url(Table *t, TableCell *cell, const char *url) {
_cleanup_free_ char *copy = NULL;
int r;
return -ENOMEM;
nd->color = od->color;
+ nd->rgap_color = od->rgap_color;
nd->url = TAKE_PTR(curl);
nd->uppercase = od->uppercase;
break;
}
+ case TABLE_SET_RGAP_COLOR: {
+ const char *c = va_arg(ap, const char*);
+ r = table_set_rgap_color(t, last_cell, c);
+ break;
+ }
+
+ case TABLE_SET_BOTH_COLORS: {
+ const char *c = va_arg(ap, const char*);
+
+ r = table_set_color(t, last_cell, c);
+ if (r < 0) {
+ va_end(ap);
+ return r;
+ }
+
+ r = table_set_rgap_color(t, last_cell, c);
+ break;
+ }
+
case TABLE_SET_URL: {
const char *u = va_arg(ap, const char*);
r = table_set_url(t, last_cell, u);
return CMP(*a, *b);
}
-static const char *table_data_format(Table *t, TableData *d) {
+static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercasing) {
assert(d);
if (d->formatted)
case TABLE_STRING:
case TABLE_PATH:
- if (d->uppercase) {
+ if (d->uppercase && !avoid_uppercasing) {
char *p, *q;
d->formatted = new(char, strlen(d->string) + 1);
case TABLE_STRV: {
char *p;
+ if (strv_isempty(d->strv))
+ return strempty(t->empty_string);
+
p = strv_join(d->strv, "\n");
if (!p)
return NULL;
const char *t;
int r;
- t = table_data_format(table, d);
+ t = table_data_format(table, d, false);
if (!t)
return -ENOMEM;
return ret;
}
+static bool table_data_isempty(TableData *d) {
+ assert(d);
+
+ if (d->type == TABLE_EMPTY)
+ return true;
+
+ /* Let's also consider an empty strv as truly empty. */
+ if (d->type == TABLE_STRV)
+ return strv_isempty(d->strv);
+
+ /* Note that an empty string we do not consider empty here! */
+ return false;
+}
+
static const char* table_data_color(TableData *d) {
assert(d);
return d->color;
/* Let's implicitly color all "empty" cells in grey, in case an "empty_string" is set that is not empty */
- if (d->type == TABLE_EMPTY)
+ if (table_data_isempty(d))
return ansi_grey();
return NULL;
}
+static const char* table_data_rgap_color(TableData *d) {
+ assert(d);
+
+ if (d->rgap_color)
+ return d->rgap_color;
+
+ return NULL;
+}
+
int table_print(Table *t, FILE *f) {
size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width,
i, j, table_minimum_width, table_maximum_width, table_requested_width, table_effective_width,
* ellipsis. Hence, let's figure out the last line, and account for its
* length plus ellipsis. */
- field = table_data_format(t, d);
+ field = table_data_format(t, d, false);
if (!field)
return -ENOMEM;
row = t->data + i * t->n_columns;
do {
+ const char *gap_color = NULL;
more_sublines = false;
for (j = 0; j < display_columns; j++) {
_cleanup_free_ char *buffer = NULL, *extracted = NULL;
bool lines_truncated = false;
- const char *field;
+ const char *field, *color = NULL;
TableData *d;
size_t l;
assert_se(d = row[t->display_map ? t->display_map[j] : j]);
- field = table_data_format(t, d);
+ field = table_data_format(t, d, false);
if (!field)
return -ENOMEM;
field = buffer;
}
- if (row == t->data) /* underline header line fully, including the column separator */
- fputs(ansi_underline(), f);
+ if (colors_enabled()) {
+ if (gap_color)
+ fputs(gap_color, f);
+ else if (row == t->data) /* underline header line fully, including the column separator */
+ fputs(ansi_underline(), f);
+ }
if (j > 0)
- fputc(' ', f); /* column separator */
+ fputc(' ', f); /* column separator left of cell */
+
+ if (colors_enabled()) {
+ color = table_data_color(d);
- if (table_data_color(d) && colors_enabled()) {
- if (row == t->data) /* first undo header underliner */
+ /* Undo gap color */
+ if (gap_color || (color && row == t->data))
fputs(ANSI_NORMAL, f);
- fputs(table_data_color(d), f);
+ if (color)
+ fputs(color, f);
+ else if (gap_color && row == t->data) /* underline header line cell */
+ fputs(ansi_underline(), f);
}
fputs(field, f);
- if (colors_enabled() && (table_data_color(d) || row == t->data))
+ if (colors_enabled() && (color || row == t->data))
fputs(ANSI_NORMAL, f);
+
+ gap_color = table_data_rgap_color(d);
}
fputc('\n', f);
case TABLE_SIZE:
case TABLE_BPS:
- if (d->size == (size_t) -1)
+ if (d->size == (uint64_t) -1)
return json_variant_new_null(ret);
return json_variant_new_unsigned(ret, d->size);
}
}
+static char* string_to_json_field_name(const char *f) {
+ char *c, *x;
+
+ /* Tries to make a string more suitable as JSON field name. There are no strict rules defined what a
+ * field name can be hence this is a bit vague and black magic. Right now we only convert spaces to
+ * underscores and leave everything as is. */
+
+ c = strdup(f);
+ if (!c)
+ return NULL;
+
+ for (x = c; *x; x++)
+ if (isspace(*x))
+ *x = '_';
+
+ return c;
+}
+
int table_to_json(Table *t, JsonVariant **ret) {
JsonVariant **rows = NULL, **elements = NULL;
_cleanup_free_ size_t *sorted = NULL;
}
for (j = 0; j < display_columns; j++) {
+ _cleanup_free_ char *mangled = NULL;
+ const char *formatted;
TableData *d;
assert_se(d = t->data[t->display_map ? t->display_map[j] : j]);
- r = table_data_to_json(d, elements + j*2);
+ /* Field names must be strings, hence format whatever we got here as a string first */
+ formatted = table_data_format(t, d, true);
+ if (!formatted) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ /* Arbitrary strings suck as field names, try to mangle them into something more suitable hence */
+ mangled = string_to_json_field_name(formatted);
+ if (!mangled) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ r = json_variant_new_string(elements + j*2, mangled);
if (r < 0)
goto finish;
}
TABLE_SET_ALIGN_PERCENT,
TABLE_SET_ELLIPSIZE_PERCENT,
TABLE_SET_COLOR,
+ TABLE_SET_RGAP_COLOR,
+ TABLE_SET_BOTH_COLORS,
TABLE_SET_URL,
TABLE_SET_UPPERCASE,
int table_set_align_percent(Table *t, TableCell *cell, unsigned percent);
int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent);
int table_set_color(Table *t, TableCell *cell, const char *color);
+int table_set_rgap_color(Table *t, TableCell *cell, const char *color);
int table_set_url(Table *t, TableCell *cell, const char *url);
int table_set_uppercase(Table *t, TableCell *cell, bool b);
return false;
}
+bool fstab_is_extrinsic(const char *mount, const char *opts) {
+
+ /* Don't bother with the OS data itself */
+ if (PATH_IN_SET(mount,
+ "/",
+ "/usr",
+ "/etc"))
+ return true;
+
+ if (PATH_STARTSWITH_SET(mount,
+ "/run/initramfs", /* This should stay around from before we boot until after we shutdown */
+ "/proc", /* All of this is API VFS */
+ "/sys", /* … dito … */
+ "/dev")) /* … dito … */
+ return true;
+
+ /* If this is an initrd mount, and we are not in the initrd, then leave
+ * this around forever, too. */
+ if (opts && fstab_test_option(opts, "x-initrd.mount\0") && !in_initrd())
+ return true;
+
+ return false;
+}
+
int fstab_is_mount_point(const char *mount) {
_cleanup_endmntent_ FILE *f = NULL;
struct mntent *m;
#include "macro.h"
+bool fstab_is_extrinsic(const char *mount, const char *opts);
int fstab_is_mount_point(const char *mount);
int fstab_has_fstype(const char *fstype);
_cleanup_free_ char *node = NULL, *unit = NULL;
int r;
+ if (fstab_is_extrinsic(where, opts))
+ return 0;
+
if (!fstab_test_option(opts, "_netdev\0"))
return 0;
* %U the UID of the running user
* %u the username of running user
* %m the machine ID of the running system
- * %H the host name of the running system
+ * %H the hostname of the running system
* %b the boot ID of the running system
* %v `uname -r` of the running system
*/
{ 'u', specifier_user_name, NULL },
{ 'm', specifier_machine_id, NULL },
- { 'H', specifier_host_name, NULL },
{ 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
{ 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
{}
};
PRESET_DISABLE,
} PresetAction;
-typedef struct {
+struct UnitFilePresetRule {
char *pattern;
PresetAction action;
char **instances;
-} PresetRule;
-
-typedef struct {
- PresetRule *rules;
- size_t n_rules;
-} Presets;
+};
static bool unit_file_install_info_has_rules(const UnitFileInstallInfo *i) {
assert(i);
return !strv_isempty(i->also);
}
-static void presets_freep(Presets *p) {
+void unit_file_presets_freep(UnitFilePresets *p) {
size_t i;
if (!p)
int r;
assert(c);
- assert(name || path);
- if (!name)
+ if (!name) {
+ /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
+ * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
+ * but this cannot be possible in any code path (See #6119). */
+ assert_se(path);
name = basename(path);
+ }
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
return -EINVAL;
if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Unit type %s cannot be templated.", unit_type_to_string(type));
+ "%s: unit type %s cannot be templated, ignoring.", path, unit_type_to_string(type));
if (!(flags & SEARCH_LOAD)) {
r = lstat(path, &st);
break;
case UNIT_FILE_TYPE_REGULAR:
+ /* Check if the name we were querying is actually an alias */
+ if (!streq(name, basename(i->path)) && !unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
+ state = UNIT_FILE_ALIAS;
+ break;
+ }
+
r = path_is_generator(paths, i->path);
if (r < 0)
return r;
return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
}
-static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
- _cleanup_(presets_freep) Presets ps = {};
+static int read_presets(UnitFileScope scope, const char *root_dir, UnitFilePresets *presets) {
+ _cleanup_(unit_file_presets_freep) UnitFilePresets ps = {};
size_t n_allocated = 0;
_cleanup_strv_free_ char **files = NULL;
char **p;
for (;;) {
_cleanup_free_ char *line = NULL;
- PresetRule rule = {};
+ UnitFilePresetRule rule = {};
const char *parameter;
char *l;
continue;
}
- rule = (PresetRule) {
+ rule = (UnitFilePresetRule) {
.pattern = unit_name,
.action = PRESET_ENABLE,
.instances = instances,
if (!pattern)
return -ENOMEM;
- rule = (PresetRule) {
+ rule = (UnitFilePresetRule) {
.pattern = pattern,
.action = PRESET_DISABLE,
};
}
}
+ ps.initialized = true;
*presets = ps;
- ps = (Presets){};
+ ps = (UnitFilePresets){};
return 0;
}
static int pattern_match_multiple_instances(
- const PresetRule rule,
+ const UnitFilePresetRule rule,
const char *unit_name,
char ***ret) {
return 0;
}
-static int query_presets(const char *name, const Presets presets, char ***instance_name_list) {
+static int query_presets(const char *name, const UnitFilePresets *presets, char ***instance_name_list) {
PresetAction action = PRESET_UNKNOWN;
size_t i;
char **s;
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- for (i = 0; i < presets.n_rules; i++)
- if (pattern_match_multiple_instances(presets.rules[i], name, instance_name_list) > 0 ||
- fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
- action = presets.rules[i].action;
+ for (i = 0; i < presets->n_rules; i++)
+ if (pattern_match_multiple_instances(presets->rules[i], name, instance_name_list) > 0 ||
+ fnmatch(presets->rules[i].pattern, name, FNM_NOESCAPE) == 0) {
+ action = presets->rules[i].action;
break;
}
}
}
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
- _cleanup_(presets_freep) Presets presets = {};
+int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached) {
+ _cleanup_(unit_file_presets_freep) UnitFilePresets tmp = {};
int r;
- r = read_presets(scope, root_dir, &presets);
- if (r < 0)
- return r;
+ if (!cached)
+ cached = &tmp;
+ if (!cached->initialized) {
+ r = read_presets(scope, root_dir, cached);
+ if (r < 0)
+ return r;
+ }
- return query_presets(name, presets, NULL);
+ return query_presets(name, cached, NULL);
}
static int execute_preset(
InstallContext *minus,
LookupPaths *paths,
const char *name,
- Presets presets,
+ const UnitFilePresets *presets,
UnitFileChange **changes,
size_t *n_changes) {
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(presets_freep) Presets presets = {};
+ _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
const char *config_path;
char **i;
int r;
return r;
STRV_FOREACH(i, files) {
- r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
+ r = preset_prepare_one(scope, &plus, &minus, &paths, *i, &presets, changes, n_changes);
if (r < 0)
return r;
}
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_(presets_freep) Presets presets = {};
+ _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
const char *config_path = NULL;
char **i;
int r;
continue;
/* we don't pass changes[] in, because we want to handle errors on our own */
- r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
+ r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, &presets, NULL, 0);
if (r == -ERFKILL)
r = unit_file_changes_add(changes, n_changes,
UNIT_FILE_IS_MASKED, de->d_name, NULL);
char **patterns) {
_cleanup_(lookup_paths_free) LookupPaths paths = {};
- char **i;
+ char **dirname;
int r;
assert(scope >= 0);
if (r < 0)
return r;
- STRV_FOREACH(i, paths.search_path) {
+ STRV_FOREACH(dirname, paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
- d = opendir(*i);
+ d = opendir(*dirname);
if (!d) {
if (errno == ENOENT)
continue;
if (IN_SET(errno, ENOTDIR, EACCES)) {
- log_debug_errno(errno, "Failed to open \"%s\": %m", *i);
+ log_debug_errno(errno, "Failed to open \"%s\": %m", *dirname);
continue;
}
if (!f)
return -ENOMEM;
- f->path = path_make_absolute(de->d_name, *i);
+ f->path = path_make_absolute(de->d_name, *dirname);
if (!f->path)
return -ENOMEM;
}
static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
- [UNIT_FILE_ENABLED] = "enabled",
+ [UNIT_FILE_ENABLED] = "enabled",
[UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
- [UNIT_FILE_LINKED] = "linked",
- [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
- [UNIT_FILE_MASKED] = "masked",
- [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
- [UNIT_FILE_STATIC] = "static",
- [UNIT_FILE_DISABLED] = "disabled",
- [UNIT_FILE_INDIRECT] = "indirect",
- [UNIT_FILE_GENERATED] = "generated",
- [UNIT_FILE_TRANSIENT] = "transient",
- [UNIT_FILE_BAD] = "bad",
+ [UNIT_FILE_LINKED] = "linked",
+ [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
+ [UNIT_FILE_ALIAS] = "alias",
+ [UNIT_FILE_MASKED] = "masked",
+ [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
+ [UNIT_FILE_STATIC] = "static",
+ [UNIT_FILE_DISABLED] = "disabled",
+ [UNIT_FILE_INDIRECT] = "indirect",
+ [UNIT_FILE_GENERATED] = "generated",
+ [UNIT_FILE_TRANSIENT] = "transient",
+ [UNIT_FILE_BAD] = "bad",
};
DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
- [UNIT_FILE_SYMLINK] = "symlink",
- [UNIT_FILE_UNLINK] = "unlink",
- [UNIT_FILE_IS_MASKED] = "masked",
+ [UNIT_FILE_SYMLINK] = "symlink",
+ [UNIT_FILE_UNLINK] = "unlink",
+ [UNIT_FILE_IS_MASKED] = "masked",
[UNIT_FILE_IS_DANGLING] = "dangling",
};
DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
- [UNIT_FILE_PRESET_FULL] = "full",
- [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
+ [UNIT_FILE_PRESET_FULL] = "full",
+ [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
[UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
};
int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst);
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
+typedef struct UnitFilePresetRule UnitFilePresetRule;
+
+typedef struct {
+ UnitFilePresetRule *rules;
+ size_t n_rules;
+ bool initialized;
+} UnitFilePresets;
+
+void unit_file_presets_freep(UnitFilePresets *p);
+int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
const char *unit_file_state_to_string(UnitFileState s) _const_;
UnitFileState unit_file_state_from_string(const char *s) _pure_;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <net/if.h>
+
+#include "ipvlan-util.h"
+#include "string-table.h"
+
+static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
+ [NETDEV_IPVLAN_MODE_L2] = "L2",
+ [NETDEV_IPVLAN_MODE_L3] = "L3",
+ [NETDEV_IPVLAN_MODE_L3S] = "L3S",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
+
+static const char* const ipvlan_flags_table[_NETDEV_IPVLAN_FLAGS_MAX] = {
+ [NETDEV_IPVLAN_FLAGS_BRIGDE] = "bridge",
+ [NETDEV_IPVLAN_FLAGS_PRIVATE] = "private",
+ [NETDEV_IPVLAN_FLAGS_VEPA] = "vepa",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ipvlan_flags, IPVlanFlags);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <netinet/in.h>
+#include <linux/if_link.h>
+
+#include "macro.h"
+
+typedef enum IPVlanMode {
+ NETDEV_IPVLAN_MODE_L2 = IPVLAN_MODE_L2,
+ NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3,
+ NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S,
+ _NETDEV_IPVLAN_MODE_MAX,
+ _NETDEV_IPVLAN_MODE_INVALID = -1
+} IPVlanMode;
+
+typedef enum IPVlanFlags {
+ NETDEV_IPVLAN_FLAGS_BRIGDE,
+ NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE,
+ NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA,
+ _NETDEV_IPVLAN_FLAGS_MAX,
+ _NETDEV_IPVLAN_FLAGS_INVALID = -1
+} IPVlanFlags;
+
+const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
+IPVlanMode ipvlan_mode_from_string(const char *d) _pure_;
+
+const char *ipvlan_flags_to_string(IPVlanFlags d) _const_;
+IPVlanFlags ipvlan_flags_from_string(const char *d) _pure_;
v->sensitive = true;
}
+bool json_variant_is_sensitive(JsonVariant *v) {
+ v = json_variant_formalize(v);
+ if (!json_variant_is_regular(v))
+ return false;
+
+ return v->sensitive;
+}
+
+static void json_variant_propagate_sensitive(JsonVariant *from, JsonVariant *to) {
+ if (json_variant_is_sensitive(from))
+ json_variant_sensitive(to);
+}
+
int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column) {
assert_return(v, -EINVAL);
if (r < 0)
return r;
+ json_variant_propagate_sensitive(*v, w);
+
json_variant_unref(*v);
*v = TAKE_PTR(w);
if (r < 0)
return r;
+ json_variant_propagate_sensitive(*v, w);
+
json_variant_unref(*v);
*v = TAKE_PTR(w);
if (r < 0)
return r;
+ json_variant_propagate_sensitive(*v, w);
+ json_variant_propagate_sensitive(m, w);
+
json_variant_unref(*v);
*v = TAKE_PTR(w);
r = json_variant_new_array(&nv, array, i + 1);
}
-
if (r < 0)
return r;
+ json_variant_propagate_sensitive(*v, nv);
+
json_variant_unref(*v);
*v = TAKE_PTR(nv);
memcpy_safe(&c->value, source, k);
+ json_variant_propagate_sensitive(v, c);
+
*nv = c;
return 0;
}
r = json_variant_new_object(&n, a, m);
if (r < 0)
return r;
+
+ json_variant_propagate_sensitive(*v, n);
+
if (!n->sorted) /* Check if this worked. This will fail if there are multiple identical keys used. */
return -ENOTUNIQ;
}
if (r < 0)
goto finish;
+
+ json_variant_propagate_sensitive(*v, n);
+
if (!n->normalized) { /* Let's see if normalization worked. It will fail if there are multiple
* identical keys used in the same object anywhere, or if there are floating
* point numbers used (see below) */
bool json_variant_equal(JsonVariant *a, JsonVariant *b);
void json_variant_sensitive(JsonVariant *v);
+bool json_variant_is_sensitive(JsonVariant *v);
struct json_variant_foreach_state {
JsonVariant *variant;
return 0;
}
-static int field_set_test(Set *fields, const char *name, size_t n) {
- char *s = NULL;
+static int field_set_test(const Set *fields, const char *name, size_t n) {
+ char *s;
if (!fields)
return 1;
if (!s)
return log_oom();
- return set_get(fields, s) ? 1 : 0;
+ return set_contains(fields, s);
}
static bool shall_print(const char *p, size_t l, OutputFlags flags) {
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields,
+ const Set *output_fields,
const size_t highlight[2]) {
int r;
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields,
+ const Set *output_fields,
const size_t highlight[2]) {
const void *data;
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields,
+ const Set *output_fields,
const size_t highlight[2]) {
sd_id128_t boot_id;
static int update_json_data_split(
Hashmap *h,
OutputFlags flags,
- Set *output_fields,
+ const Set *output_fields,
const void *data,
size_t size) {
return 0;
name = strndupa(data, eq - (const char*) data);
- if (output_fields && !set_get(output_fields, name))
+ if (output_fields && !set_contains(output_fields, name))
return 0;
return update_json_data(h, flags, name, eq + 1, size - (eq - (const char*) data) - 1);
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields,
+ const Set *output_fields,
const size_t highlight[2]) {
char sid[SD_ID128_STRING_MAX], usecbuf[DECIMAL_STR_MAX(usec_t)];
return r;
}
-static int output_cat(
+static int output_cat_field(
FILE *f,
sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
OutputFlags flags,
- Set *output_fields,
+ const char *field,
const size_t highlight[2]) {
+ const char *highlight_on, *highlight_off;
const void *data;
- size_t l;
+ size_t l, fl;
int r;
- const char *highlight_on = "", *highlight_off = "";
-
- assert(j);
- assert(f);
- if (flags & OUTPUT_COLOR) {
+ if (FLAGS_SET(flags, OUTPUT_COLOR)) {
highlight_on = ANSI_HIGHLIGHT_RED;
highlight_off = ANSI_NORMAL;
- }
-
- sd_journal_set_data_threshold(j, 0);
+ } else
+ highlight_on = highlight_off = "";
- r = sd_journal_get_data(j, "MESSAGE", &data, &l);
+ r = sd_journal_get_data(j, field, &data, &l);
if (r == -EBADMSG) {
log_debug_errno(r, "Skipping message we can't read: %m");
return 0;
}
- if (r < 0) {
- /* An entry without MESSAGE=? */
- if (r == -ENOENT)
- return 0;
-
+ if (r == -ENOENT) /* An entry without the requested field */
+ return 0;
+ if (r < 0)
return log_error_errno(r, "Failed to get data: %m");
- }
- assert(l >= 8);
+ fl = strlen(field);
+ assert(l >= fl + 1);
+ assert(((char*) data)[fl] == '=');
+
+ data = (const uint8_t*) data + fl + 1;
+ l -= fl + 1;
- if (highlight && (flags & OUTPUT_COLOR)) {
+ if (highlight && FLAGS_SET(flags, OUTPUT_COLOR)) {
assert(highlight[0] <= highlight[1]);
- assert(highlight[1] <= l - 8);
+ assert(highlight[1] <= l);
- fwrite((const char*) data + 8, 1, highlight[0], f);
+ fwrite((const char*) data, 1, highlight[0], f);
fwrite(highlight_on, 1, strlen(highlight_on), f);
- fwrite((const char*) data + 8 + highlight[0], 1, highlight[1] - highlight[0], f);
+ fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
fwrite(highlight_off, 1, strlen(highlight_off), f);
- fwrite((const char*) data + 8 + highlight[1], 1, l - 8 - highlight[1], f);
+ fwrite((const char*) data + highlight[1], 1, l - highlight[1], f);
} else
- fwrite((const char*) data + 8, 1, l - 8, f);
+ fwrite((const char*) data, 1, l, f);
+
fputc('\n', f);
+ return 0;
+}
+
+static int output_cat(
+ FILE *f,
+ sd_journal *j,
+ OutputMode mode,
+ unsigned n_columns,
+ OutputFlags flags,
+ const Set *output_fields,
+ const size_t highlight[2]) {
+
+ const char *field;
+ Iterator iterator;
+ int r;
+
+ assert(j);
+ assert(f);
+
+ (void) sd_journal_set_data_threshold(j, 0);
+
+ if (set_isempty(output_fields))
+ return output_cat_field(f, j, flags, "MESSAGE", highlight);
+
+ SET_FOREACH(field, output_fields, iterator) {
+ r = output_cat_field(f, j, flags, field, streq(field, "MESSAGE") ? highlight : NULL);
+ if (r < 0)
+ return r;
+ }
return 0;
}
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields,
+ const Set *output_fields,
const size_t highlight[2]) = {
[OUTPUT_SHORT] = output_short,
const size_t highlight[2],
bool *ellipsized) {
- int ret;
- _cleanup_set_free_free_ Set *fields = NULL;
+ _cleanup_set_free_ Set *fields = NULL;
+ int r;
+
assert(mode >= 0);
assert(mode < _OUTPUT_MODE_MAX);
if (n_columns <= 0)
n_columns = columns();
- if (output_fields) {
- fields = set_new(&string_hash_ops);
- if (!fields)
- return log_oom();
-
- ret = set_put_strdupv(fields, output_fields);
- if (ret < 0)
- return ret;
- }
+ r = set_put_strdupv(&fields, output_fields);
+ if (r < 0)
+ return r;
- ret = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
+ r = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
- if (ellipsized && ret > 0)
+ if (ellipsized && r > 0)
*ellipsized = true;
- return ret;
+ return r;
}
static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "conf-parser.h"
+#include "macvlan-util.h"
+#include "string-table.h"
+
+static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
+ [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
+ [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
+ [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
+ [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/if_link.h>
+
+typedef enum MacVlanMode {
+ NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
+ NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
+ NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
+ NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
+ _NETDEV_MACVLAN_MODE_MAX,
+ _NETDEV_MACVLAN_MODE_INVALID = -1
+} MacVlanMode;
+
+const char *macvlan_mode_to_string(MacVlanMode d) _const_;
+MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
barrier.h
base-filesystem.c
base-filesystem.h
+ binfmt-util.c
+ binfmt-util.h
bitmap.c
bitmap.h
blkid-util.h
+ bond-util.c
+ bond-util.h
boot-timestamps.c
boot-timestamps.h
bootspec.c
bpf-program.h
bridge-util.c
bridge-util.h
+ bus-locator.c
+ bus-locator.h
bus-log-control-api.c
bus-log-control-api.h
bus-polkit.c
install-printf.h
install.c
install.h
+ ipvlan-util.c
+ ipvlan-util.h
ip-protocol-list.c
ip-protocol-list.h
journal-importer.c
machine-image.h
machine-pool.c
machine-pool.h
+ macvlan-util.c
+ macvlan-util.h
main-func.h
module-util.h
mount-util.c
securebits-util.h
serialize.c
serialize.h
+ service-util.c
+ service-util.h
sleep-config.c
sleep-config.h
socket-netlink.c
librt,
libseccomp,
libselinux,
+ libzstd,
libxz]
libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir())
}
if (!set_contains(done, path)) {
- r = set_put_strdup(todo, path);
+ r = set_put_strdup(&todo, path);
if (r < 0)
return r;
}
log_debug("Made top-level directory %s a mount point.", prefix);
- r = set_put_strdup(done, simplified);
+ r = set_put_strdup(&done, simplified);
if (r < 0)
return r;
}
#include "macro.h"
+/* 4MB for contents of regular files, 64k inodes for directories, symbolic links and device specials,
+ using large storage array systems as a baseline */
+#define TMPFS_LIMITS_DEV ",size=4m,nr_inodes=64k"
+/* Very little, if any use expected */
+#define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k"
+#define TMPFS_LIMITS_SYS TMPFS_LIMITS_EMPTY_OR_ALMOST
+#define TMPFS_LIMITS_SYS_FS_CGROUP TMPFS_LIMITS_EMPTY_OR_ALMOST
+/* On an extremely small device with only 256MB of RAM, 20% of RAM for /run should be enough for re-exec of
+ PID1 because 16MB of free space is required. */
+#define TMPFS_LIMITS_RUN ",size=20%,nr_inodes=800k"
+/* 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25%
+ translates to 1M inodes */
+#define TMPFS_LIMITS_TMP ",size=10%,nr_inodes=400k"
+#define TMPFS_LIMITS_DEV_SHM TMPFS_LIMITS_TMP
+#define TMPFS_LIMITS_TEMPORARY_FS TMPFS_LIMITS_TMP
+/* More space for volatile root and /var */
+#define TMPFS_LIMITS_VAR ",size=25%,nr_inodes=1m"
+#define TMPFS_LIMITS_ROOTFS TMPFS_LIMITS_VAR
+#define TMPFS_LIMITS_VOLATILE_STATE TMPFS_LIMITS_VAR
+
int repeat_unmount(const char *path, int flags);
int umount_recursive(const char *target, int flags);
int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist);
int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
struct statfs sfs;
- int r;
assert(fd >= 0);
sz -= sz % sfs.f_bsize;
- r = snprintf(args.name, sizeof(args.name), "%" PRIu64, sz);
- assert((size_t) r < sizeof(args.name));
+ xsprintf(args.name, "%" PRIu64, sz);
if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
return -errno;
.value =
"lookup_dcookie\0"
"perf_event_open\0"
+ "pidfd_getfd\0"
"ptrace\0"
"rtas\0"
#ifdef __NR_s390_runtime_instr
"oldstat\0"
"open\0"
"openat\0"
+ "openat2\0"
"readlink\0"
"readlinkat\0"
"removexattr\0"
}
int parse_syscall_archs(char **l, Set **archs) {
- _cleanup_set_free_ Set *_archs;
+ _cleanup_set_free_ Set *_archs = NULL;
char **s;
int r;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "pretty-print.h"
+#include "service-util.h"
+#include "terminal-util.h"
+#include "util.h"
+
+static int help(const char *program_path, const char *service, const char *description, bool bus_introspect) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man(service, "8", &link);
+ if (r < 0)
+ return log_oom();
+
+ printf("%s [OPTIONS...]\n\n"
+ "%s%s%s\n\n"
+ "This program takes no positional arguments.\n\n"
+ "%sOptions%s:\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --bus-introspect=PATH Write D-Bus XML introspection data\n"
+ "\nSee the %s for details.\n"
+ , program_path
+ , ansi_highlight(), description, ansi_normal()
+ , ansi_underline(), ansi_normal()
+ , link
+ );
+
+ return 0; /* No further action */
+}
+
+int service_parse_argv(
+ const char *service,
+ const char *description,
+ const BusObjectImplementation* const* bus_objects,
+ int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_BUS_INTROSPECT,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+ switch(c) {
+
+ case 'h':
+ return help(argv[0], service, description, bus_objects);
+
+ case ARG_VERSION:
+ return version();
+
+ case ARG_BUS_INTROSPECT:
+ return bus_introspect_implementations(
+ stdout,
+ optarg,
+ bus_objects);
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unknown option code.");
+ }
+
+ if (optind < argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program takes no arguments.");
+
+ return 1; /* Further action */
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "bus-util.h"
+
+int service_parse_argv(
+ const char *service,
+ const char *description,
+ const BusObjectImplementation* const* bus_objects,
+ int argc, char *argv[]);
assert(a);
assert(s);
- zero(*a);
- a->type = SOCK_RAW;
+ *a = (SocketAddress) {
+ .type = SOCK_RAW,
+ };
r = extract_first_word(&s, &word, NULL, 0);
if (r < 0)
return r;
}
+
+int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
+ _cleanup_free_ char *buf = NULL, *name = NULL;
+ const char *m;
+ int r;
+
+ assert(s);
+
+ m = strchr(s, '#');
+ if (m) {
+ name = strdup(m+1);
+ if (!name)
+ return -ENOMEM;
+
+ buf = strndup(s, m - s);
+ if (!buf)
+ return -ENOMEM;
+
+ s = buf;
+ }
+
+ r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
+ if (r < 0)
+ return r;
+
+ if (server_name)
+ *server_name = TAKE_PTR(name);
+
+ return r;
+}
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
+int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
#include "sd-id128.h"
#include "alloc-util.h"
+#include "architecture.h"
#include "format-util.h"
#include "fs-util.h"
#include "hostname-util.h"
#include "macro.h"
+#include "os-util.h"
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
return 0;
}
+int specifier_short_host_name(char specifier, const void *data, const void *userdata, char **ret) {
+ char *n;
+
+ n = gethostname_short_malloc();
+ if (!n)
+ return -ENOMEM;
+
+ *ret = n;
+ return 0;
+}
+
int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret) {
struct utsname uts;
char *n;
return 0;
}
+int specifier_architecture(char specifier, const void *data, const void *userdata, char **ret) {
+ char *t;
+
+ t = strdup(architecture_to_string(uname_architecture()));
+ if (!t)
+ return -ENOMEM;
+
+ *ret = t;
+ return 0;
+}
+
+static int specifier_os_release_common(const char *field, char **ret) {
+ char *t = NULL;
+ int r;
+
+ r = parse_os_release(NULL, field, &t, NULL);
+ if (r < 0)
+ return r;
+ if (!t) {
+ /* fields in /etc/os-release might quite possibly be missing, even if everything is entirely
+ * valid otherwise. Let's hence return "" in that case. */
+ t = strdup("");
+ if (!t)
+ return -ENOMEM;
+ }
+
+ *ret = t;
+ return 0;
+}
+
+int specifier_os_id(char specifier, const void *data, const void *userdata, char **ret) {
+ return specifier_os_release_common("ID", ret);
+}
+
+int specifier_os_version_id(char specifier, const void *data, const void *userdata, char **ret) {
+ return specifier_os_release_common("VERSION_ID", ret);
+}
+
+int specifier_os_build_id(char specifier, const void *data, const void *userdata, char **ret) {
+ return specifier_os_release_common("BUILD_ID", ret);
+}
+
+int specifier_os_variant_id(char specifier, const void *data, const void *userdata, char **ret) {
+ return specifier_os_release_common("VARIANT_ID", ret);
+}
+
int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret) {
char *t;
int specifier_machine_id(char specifier, const void *data, const void *userdata, char **ret);
int specifier_boot_id(char specifier, const void *data, const void *userdata, char **ret);
int specifier_host_name(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_short_host_name(char specifier, const void *data, const void *userdata, char **ret);
int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_architecture(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_id(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_version_id(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_build_id(char specifier, const void *data, const void *userdata, char **ret);
+int specifier_os_variant_id(char specifier, const void *data, const void *userdata, char **ret);
int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret);
int specifier_group_id(char specifier, const void *data, const void *userdata, char **ret);
/* We don't explicitly check for alias loops here. unit_ids_map_get() which
* limits the number of hops should be used to access the map. */
- _cleanup_free_ char *target = NULL, *target_abs = NULL;
+ _cleanup_free_ char *target = NULL;
r = readlinkat_malloc(dirfd(d), de->d_name, &target);
if (r < 0) {
continue;
}
- if (!path_is_absolute(target)) {
- target_abs = path_join(*dir, target);
+ const bool is_abs = path_is_absolute(target);
+ if (lp->root_dir || !is_abs) {
+ char *target_abs = path_join(is_abs ? lp->root_dir : *dir, target);
if (!target_abs)
return log_oom();
/* The unit always has its own name if it's not a template. */
if (IN_SET(name_type, UNIT_NAME_PLAIN, UNIT_NAME_INSTANCE)) {
- r = set_put_strdup(names, unit_name);
+ r = set_put_strdup(&names, unit_name);
if (r < 0)
return r;
}
if (!streq(unit_name, *t))
log_debug("%s: %s has alias %s", __func__, unit_name, *t);
- r = set_put_strdup(names, *t);
+ r = set_put_strdup(&names, *t);
}
if (r < 0)
return r;
UNIT_FILE_ENABLED_RUNTIME,
UNIT_FILE_LINKED,
UNIT_FILE_LINKED_RUNTIME,
+ UNIT_FILE_ALIAS,
UNIT_FILE_MASKED,
UNIT_FILE_MASKED_RUNTIME,
UNIT_FILE_STATIC,
printf(" Access Mode: 0%03oo\n", user_record_access_mode(hr));
if (storage == USER_LUKS) {
- printf("LUKS Discard: %s\n", yes_no(user_record_luks_discard(hr)));
+ printf("LUKS Discard: online=%s offline=%s\n", yes_no(user_record_luks_discard(hr)), yes_no(user_record_luks_offline_discard(hr)));
if (!sd_id128_is_null(hr->luks_uuid))
printf(" LUKS UUID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(hr->luks_uuid));
if (hr->disk_usage != UINT64_MAX) {
char buf[FORMAT_BYTES_MAX];
- printf(" Disk Usage: %s\n", format_bytes(buf, sizeof(buf), hr->disk_usage));
+
+ if (hr->disk_size != UINT64_MAX) {
+ unsigned permille;
+
+ permille = (unsigned) DIV_ROUND_UP(hr->disk_usage * 1000U, hr->disk_size); /* Round up! */
+ printf(" Disk Usage: %s (= %u.%01u%%)\n",
+ format_bytes(buf, sizeof(buf), hr->disk_usage),
+ permille / 10, permille % 10);
+ } else
+ printf(" Disk Usage: %s\n", format_bytes(buf, sizeof(buf), hr->disk_usage));
}
if (hr->disk_free != UINT64_MAX) {
char buf[FORMAT_BYTES_MAX];
- printf(" Disk Free: %s\n", format_bytes(buf, sizeof(buf), hr->disk_free));
+
+ if (hr->disk_size != UINT64_MAX) {
+ const char *color_on, *color_off;
+ unsigned permille;
+
+ permille = (unsigned) ((hr->disk_free * 1000U) / hr->disk_size); /* Round down! */
+
+ /* Color the output red or yellow if we are below 10% resp. 25% free. Because 10% and
+ * 25% can be a lot of space still, let's additionally make some absolute
+ * restrictions: 1G and 2G */
+ if (permille <= 100U &&
+ hr->disk_free < 1024U*1024U*1024U /* 1G */) {
+ color_on = ansi_highlight_red();
+ color_off = ansi_normal();
+ } else if (permille <= 250U &&
+ hr->disk_free < 2U*1024U*1024U*1024U /* 2G */) {
+ color_on = ansi_highlight_yellow();
+ color_off = ansi_normal();
+ } else
+ color_on = color_off = "";
+
+ printf(" Disk Free: %s%s (= %u.%01u%%)%s\n",
+ color_on,
+ format_bytes(buf, sizeof(buf), hr->disk_free),
+ permille / 10, permille % 10,
+ color_off);
+ } else
+ printf(" Disk Free: %s\n", format_bytes(buf, sizeof(buf), hr->disk_free));
}
if (hr->disk_floor != UINT64_MAX) {
.nodev = true,
.nosuid = true,
.luks_discard = -1,
+ .luks_offline_discard = -1,
.luks_volume_key_size = UINT64_MAX,
.luks_pbkdf_time_cost_usec = UINT64_MAX,
.luks_pbkdf_memory_cost = UINT64_MAX,
{ "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
{ "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
{ "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0, },
+ { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0, },
{ "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
{ "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
{ "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
}
+int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
+ const char *suffix;
+ char *z;
+
+ assert(storage >= 0);
+ assert(user_name_and_realm);
+ assert(ret);
+
+ if (storage == USER_LUKS)
+ suffix = ".home";
+ else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
+ suffix = ".homedir";
+ else {
+ *ret = NULL;
+ return 0;
+ }
+
+ z = strjoin("/home/", user_name_and_realm, suffix);
+ if (!z)
+ return -ENOMEM;
+
+ *ret = z;
+ return 1;
+}
+
static int user_record_augment(UserRecord *h, JsonDispatchFlags json_flags) {
+ int r;
+
assert(h);
if (!FLAGS_SET(h->mask, USER_RECORD_REGULAR))
}
if (!h->image_path && !h->image_path_auto) {
- const char *suffix;
- UserStorage storage;
-
- storage = user_record_storage(h);
- if (storage == USER_LUKS)
- suffix = ".home";
- else if (IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT))
- suffix = ".homedir";
- else
- suffix = NULL;
-
- if (suffix) {
- h->image_path_auto = strjoin("/home/", user_record_user_name_and_realm(h), suffix);
- if (!h->image_path_auto)
- return json_log_oom(h->json, json_flags);
- }
+ r = user_record_build_image_path(user_record_storage(h), user_record_user_name_and_realm(h), &h->image_path_auto);
+ if (r < 0)
+ return json_log(h->json, json_flags, r, "Failed to determine default image path: %m");
}
return 0;
{ "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
{ "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 },
{ "luksDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_discard), 0 },
+ { "luksOfflineDiscard", _JSON_VARIANT_TYPE_INVALID, json_dispatch_tristate, offsetof(UserRecord, luks_offline_discard), 0 },
{ "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE },
{ "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE },
{ "luksVolumeKeySize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_volume_key_size), 0 },
return path_startswith(ip, "/dev/");
}
+bool user_record_luks_offline_discard(UserRecord *h) {
+ const char *ip;
+
+ assert(h);
+
+ if (h->luks_offline_discard >= 0)
+ return h->luks_offline_discard;
+
+ /* Discard while we are logged out should generally be a good idea, except when operating directly on
+ * physical media, where we should just bind it to the online discard mode. */
+
+ ip = user_record_image_path(h);
+ if (!ip)
+ return false;
+
+ if (path_startswith(ip, "/dev/"))
+ return user_record_luks_discard(h);
+
+ return true;
+}
+
const char *user_record_luks_cipher(UserRecord *h) {
assert(h);
sd_id128_t file_system_uuid;
int luks_discard;
+ int luks_offline_discard;
char *luks_cipher;
char *luks_cipher_mode;
uint64_t luks_volume_key_size;
const char *user_record_shell(UserRecord *h);
const char *user_record_real_name(UserRecord *h);
bool user_record_luks_discard(UserRecord *h);
+bool user_record_luks_offline_discard(UserRecord *h);
const char *user_record_luks_cipher(UserRecord *h);
const char *user_record_luks_cipher_mode(UserRecord *h);
uint64_t user_record_luks_volume_key_size(UserRecord *h);
uint64_t user_record_ratelimit_burst(UserRecord *h);
bool user_record_can_authenticate(UserRecord *h);
+int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret);
+
bool user_record_equal(UserRecord *a, UserRecord *b);
bool user_record_compatible(UserRecord *a, UserRecord *b);
int user_record_compare_last_change(UserRecord *a, UserRecord *b);
return r > 0;
}
+const Verb* verbs_find_verb(const char *name, const Verb verbs[]) {
+ for (size_t i = 0; verbs[i].dispatch; i++)
+ if (streq_ptr(name, verbs[i].verb) ||
+ (!name && FLAGS_SET(verbs[i].flags, VERB_DEFAULT)))
+ return &verbs[i];
+
+ /* At the end of the list? */
+ return NULL;
+}
+
int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
const Verb *verb;
const char *name;
- unsigned i;
int left;
assert(verbs);
optind = 0;
name = argv[0];
- for (i = 0;; i++) {
- bool found;
-
- /* At the end of the list? */
- if (!verbs[i].dispatch) {
- if (name)
- log_error("Unknown operation %s.", name);
- else
- log_error("Requires operation parameter.");
- return -EINVAL;
- }
-
+ verb = verbs_find_verb(name, verbs);
+ if (!verb) {
if (name)
- found = streq(name, verbs[i].verb);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown command verb %s.", name);
else
- found = verbs[i].flags & VERB_DEFAULT;
-
- if (found) {
- verb = &verbs[i];
- break;
- }
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Command verb required.");
}
- assert(verb);
-
if (!name)
left = 1;
"Too many arguments.");
if ((verb->flags & VERB_ONLINE_ONLY) && running_in_chroot_or_offline()) {
- if (name)
- log_info("Running in chroot, ignoring request: %s", name);
- else
- log_info("Running in chroot, ignoring request.");
+ log_info("Running in chroot, ignoring command '%s'", name ?: verb->verb);
return 0;
}
#define VERB_ANY ((unsigned) -1)
typedef enum VerbFlags {
- VERB_DEFAULT = 1 << 0,
- VERB_ONLINE_ONLY = 1 << 1,
+ VERB_DEFAULT = 1 << 0, /* The verb to run if no verb is specified */
+ VERB_ONLINE_ONLY = 1 << 1, /* Just do nothing when running in chroot or offline */
} VerbFlags;
typedef struct {
bool running_in_chroot_or_offline(void);
+const Verb* verbs_find_verb(const char *name, const Verb verbs[]);
int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata);
#include "alloc-util.h"
#include "async.h"
+#include "binfmt-util.h"
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "def.h"
sync_with_progress();
disable_coredumps();
+ disable_binfmt();
log_info("Sending SIGTERM to remaining processes...");
broadcast_signal(SIGTERM, true, true, arg_timeout);
}
if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
- log_error("Failed to finalize %s%s%s%s ignoring",
+ log_error("Failed to finalize%s%s%s%s ignoring.",
need_umount ? " file systems," : "",
need_swapoff ? " swap devices," : "",
need_loop_detach ? " loop devices," : "",
static unsigned arg_connections_max = 256;
static const char *arg_remote_host = NULL;
+static usec_t arg_exit_idle_time = USEC_INFINITY;
typedef struct Context {
sd_event *event;
sd_resolve *resolve;
+ sd_event_source *idle_time;
Set *listen;
Set *connections;
free(c);
}
+static int idle_time_cb(sd_event_source *s, uint64_t usec, void *userdata) {
+ Context *c = userdata;
+ int r;
+
+ if (!set_isempty(c->connections)) {
+ log_warning("Idle timer fired even though there are connections, ignoring");
+ return 0;
+ }
+
+ r = sd_event_exit(c->event, 0);
+ if (r < 0) {
+ log_warning_errno(r, "Error while stopping event loop, ignoring: %m");
+ return 0;
+ }
+ return 0;
+}
+
+static int connection_release(Connection *c) {
+ int r;
+ Context *context = c->context;
+ usec_t idle_instant;
+
+ connection_free(c);
+
+ if (arg_exit_idle_time < USEC_INFINITY && set_isempty(context->connections)) {
+ idle_instant = usec_add(now(CLOCK_MONOTONIC), arg_exit_idle_time);
+ if (context->idle_time) {
+ r = sd_event_source_set_time(context->idle_time, idle_instant);
+ if (r < 0)
+ return log_error_errno(r, "Error while setting idle time: %m");
+
+ r = sd_event_source_set_enabled(context->idle_time, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "Error while enabling idle time: %m");
+ } else {
+ r = sd_event_add_time(context->event, &context->idle_time, CLOCK_MONOTONIC,
+ idle_instant, 0, idle_time_cb, context);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create idle timer: %m");
+ }
+ }
+
+ return 0;
+}
+
static void context_clear(Context *context) {
assert(context);
sd_event_unref(context->event);
sd_resolve_unref(context->resolve);
+ sd_event_source_unref(context->idle_time);
}
static int connection_create_pipes(Connection *c, int buffer[static 2], size_t *sz) {
return 1;
quit:
- connection_free(c);
+ connection_release(c);
return 0; /* ignore errors, continue serving */
}
return 0;
fail:
- connection_free(c);
+ connection_release(c);
return 0; /* ignore errors, continue serving */
}
return connection_complete(c);
fail:
- connection_free(c);
+ connection_release(c);
return 0; /* ignore errors, continue serving */
}
return 0;
fail:
- connection_free(c);
+ connection_release(c);
return 0; /* ignore errors, continue serving */
}
return connection_start(c, ai->ai_addr, ai->ai_addrlen);
fail:
- connection_free(c);
+ connection_release(c);
return 0; /* ignore errors, continue serving */
}
return 0;
fail:
- connection_free(c);
+ connection_release(c);
return 0; /* ignore errors, continue serving */
}
return 0;
}
+ if (context->idle_time) {
+ r = sd_event_source_set_enabled(context->idle_time, SD_EVENT_OFF);
+ if (r < 0)
+ log_warning_errno(r, "Unable to disable idle timer, continuing: %m");
+ }
+
r = set_ensure_allocated(&context->connections, NULL);
if (r < 0) {
log_oom();
static int help(void) {
_cleanup_free_ char *link = NULL;
+ _cleanup_free_ char *time_link = NULL;
int r;
r = terminal_urlify_man("systemd-socket-proxyd", "8", &link);
+ if (r < 0)
+ return log_oom();
+ r = terminal_urlify_man("systemd.time", "7", &time_link);
if (r < 0)
return log_oom();
"%1$s [SOCKET]\n\n"
"Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
" -c --connections-max= Set the maximum number of connections to be accepted\n"
+ " --exit-idle-time= Exit when without a connection for this duration. See\n"
+ " the %3$s for time span format\n"
" -h --help Show this help\n"
" --version Show package version\n"
"\nSee the %2$s for details.\n"
, program_invocation_short_name
, link
+ , time_link
);
return 0;
enum {
ARG_VERSION = 0x100,
+ ARG_EXIT_IDLE,
ARG_IGNORE_ENV
};
static const struct option options[] = {
{ "connections-max", required_argument, NULL, 'c' },
+ { "exit-idle-time", required_argument, NULL, ARG_EXIT_IDLE },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{}
break;
+ case ARG_EXIT_IDLE:
+ r = parse_sec(optarg, &arg_exit_idle_time);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --exit-idle-time= argument: %s", optarg);
+ break;
+
case '?':
return -EINVAL;
if (!pattern)
return log_oom();
- k = glob_extend(&paths, pattern);
+ k = glob_extend(&paths, pattern, GLOB_NOCHECK);
if (k < 0) {
- if (option->ignore_failure || ERRNO_IS_PRIVILEGE(r))
+ if (option->ignore_failure || ERRNO_IS_PRIVILEGE(k))
log_debug_errno(k, "Failed to resolve glob '%s', ignoring: %m",
option->key);
else {
return true;
}
+static int output_table(Table *table) {
+ int r;
+
+ assert(table);
+
+ if (OUTPUT_MODE_IS_JSON(arg_output))
+ r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
+ else
+ r = table_print(table, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to show table: %m");
+
+ return 0;
+}
+
static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
_cleanup_(table_unrefp) Table *table = NULL;
const UnitInfo *u;
if (arg_full)
table_set_width(table, 0);
- for (u = unit_infos; u < unit_infos + c; u++) {
+ (void) table_set_empty_string(table, "-");
+
+ for (u = unit_infos; unit_infos && u < unit_infos + c; u++) {
_cleanup_free_ char *j = NULL;
const char *on_underline = "", *on_loaded = "", *on_active = "";
const char *on_circle = "", *id;
}
if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
- on_circle = ansi_highlight_yellow();
+ on_circle = underline ? ansi_highlight_yellow_underline() : ansi_highlight_yellow();
circle = true;
on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
} else if (streq(u->active_state, "failed") && !arg_plain) {
- on_circle = ansi_highlight_red();
+ on_circle = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
circle = true;
on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
} else {
+ on_circle = on_underline;
on_active = on_underline;
on_loaded = on_underline;
}
r = table_add_many(table,
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
- TABLE_SET_COLOR, on_circle,
+ TABLE_SET_BOTH_COLORS, on_circle,
TABLE_STRING, id,
- TABLE_SET_COLOR, on_active,
+ TABLE_SET_BOTH_COLORS, on_active,
TABLE_STRING, u->load_state,
- TABLE_SET_COLOR, on_loaded,
+ TABLE_SET_BOTH_COLORS, on_loaded,
TABLE_STRING, u->active_state,
- TABLE_SET_COLOR, on_active,
+ TABLE_SET_BOTH_COLORS, on_active,
TABLE_STRING, u->sub_state,
- TABLE_SET_COLOR, on_active,
+ TABLE_SET_BOTH_COLORS, on_active,
TABLE_STRING, u->job_id ? u->job_type: "",
- TABLE_SET_COLOR, u->job_id ? on_underline : "",
+ TABLE_SET_BOTH_COLORS, u->job_id ? on_underline : "",
TABLE_STRING, u->description,
- TABLE_SET_COLOR, on_underline);
+ TABLE_SET_BOTH_COLORS, on_underline);
if (r < 0)
return table_log_add_error(r);
return log_error_errno(r, "Failed to hide column: %m");
}
- r = table_print(table, NULL);
+ r = output_table(table);
if (r < 0)
- return log_error_errno(r, "Failed to print the table: %m");
+ return r;
if (!arg_no_legend) {
const char *on, *off;
assert(unit_infos);
assert(_reply);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnitsByPatterns");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsByPatterns");
if (r < 0)
return bus_log_create_error(r);
m = sd_bus_message_unref(m);
sd_bus_error_free(&error);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnitsFiltered");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsFiltered");
if (r < 0)
return bus_log_create_error(r);
const char *on, *off;
int r;
- table = table_new("listen", "type", "units", "activates");
+ table = table_new("listen", "type", "unit", "activates");
if (!table)
return log_oom();
if (arg_full)
table_set_width(table, 0);
+ (void) table_set_empty_string(table, "-");
+
if (cs) {
for (s = socket_infos; s < socket_infos + cs; s++) {
- _cleanup_free_ char *j = NULL, *activates = NULL;
+ _cleanup_free_ char *j = NULL;
const char *path;
if (s->machine) {
} else
path = s->path;
- activates = strv_join(s->triggered, ", ");
- if (!activates)
- return log_oom();
-
r = table_add_many(table,
TABLE_STRING, path,
TABLE_STRING, s->type,
- TABLE_STRING, s->id,
- TABLE_STRING, activates);
+ TABLE_STRING, s->id);
if (r < 0)
return table_log_add_error(r);
+
+ if (strv_isempty(s->triggered))
+ r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
+ else if (strv_length(s->triggered) == 1)
+ r = table_add_cell(table, NULL, TABLE_STRING, s->triggered[0]);
+ else
+ /* This should never happen, currently our socket units can only trigger a
+ * single unit. But let's handle this anyway, who knows what the future
+ * brings? */
+ r = table_add_cell(table, NULL, TABLE_STRV, s->triggered);
+ if (r < 0)
+ return table_log_add_error(r);
+
}
on = ansi_highlight();
off = ansi_normal();
}
- r = table_print(table, NULL);
+ r = output_table(table);
if (r < 0)
- return log_error_errno(r, "Failed to print the table: %m");
+ return r;
if (!arg_no_legend) {
printf("\n%s%u sockets listed.%s\n", on, cs, off);
if (arg_full)
table_set_width(table, 0);
+ (void) table_set_empty_string(table, "-");
+
if (n > 0) {
for (t = timer_infos; t < timer_infos + n; t++) {
_cleanup_free_ char *j = NULL, *activates = NULL;
off = ansi_normal();
}
- r = table_print(table, NULL);
+ r = output_table(table);
if (r < 0)
- return log_error_errno(r, "Failed to print the table: %m");
+ return r;
if (!arg_no_legend) {
printf("\n%s%u timers listed.%s\n", on, n, off);
return true;
}
+static bool show_preset_for_state(UnitFileState state) {
+ /* Don't show preset state in those unit file states, it'll only confuse users. */
+ return !IN_SET(state,
+ UNIT_FILE_ALIAS,
+ UNIT_FILE_STATIC,
+ UNIT_FILE_GENERATED,
+ UNIT_FILE_TRANSIENT);
+}
+
static int output_unit_file_list(const UnitFileList *units, unsigned c) {
_cleanup_(table_unrefp) Table *table = NULL;
- const UnitFileList *u;
+ _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
int r;
table = table_new("unit file", "state", "vendor preset");
if (arg_full)
table_set_width(table, 0);
- for (u = units; u < units + c; u++) {
+ (void) table_set_empty_string(table, "-");
+
+ for (const UnitFileList *u = units; u < units + c; u++) {
const char *on_underline = NULL, *on_unit_color = NULL, *id;
- const char *on_preset_color = NULL, *unit_preset_str;
bool underline;
underline = u + 1 < units + c &&
UNIT_FILE_DISABLED,
UNIT_FILE_BAD))
on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
- else if (u->state == UNIT_FILE_ENABLED)
+ else if (IN_SET(u->state,
+ UNIT_FILE_ENABLED,
+ UNIT_FILE_ALIAS))
on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
else
on_unit_color = on_underline;
id = basename(u->path);
- r = unit_file_query_preset(arg_scope, NULL, id);
- if (r < 0) {
- unit_preset_str = "n/a";
- on_preset_color = underline ? on_underline : ansi_normal();
- } else if (r == 0) {
- unit_preset_str = "disabled";
- on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
- } else {
- unit_preset_str = "enabled";
- on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
- }
-
r = table_add_many(table,
TABLE_STRING, id,
- TABLE_SET_COLOR, strempty(on_underline),
+ TABLE_SET_BOTH_COLORS, strempty(on_underline),
TABLE_STRING, unit_file_state_to_string(u->state),
- TABLE_SET_COLOR, strempty(on_unit_color),
- TABLE_STRING, unit_preset_str,
- TABLE_SET_COLOR, strempty(on_preset_color));
+ TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
+ if (r < 0)
+ return table_log_add_error(r);
+
+ if (show_preset_for_state(u->state)) {
+ const char *unit_preset_str, *on_preset_color;
+
+ r = unit_file_query_preset(arg_scope, arg_root, id, &presets);
+ if (r < 0) {
+ unit_preset_str = "n/a";
+ on_preset_color = underline ? on_underline : ansi_normal();
+ } else if (r == 0) {
+ unit_preset_str = "disabled";
+ on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+ } else {
+ unit_preset_str = "enabled";
+ on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
+ }
+
+ r = table_add_many(table,
+ TABLE_STRING, unit_preset_str,
+ TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
+ } else
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
if (r < 0)
return table_log_add_error(r);
}
- r = table_print(table, NULL);
+ r = output_table(table);
if (r < 0)
- return log_error_errno(r, "Failed to print the table: %m");
+ return r;
if (!arg_no_legend)
printf("\n%u unit files listed.\n", c);
if (r < 0)
return r;
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnitFilesByPatterns");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFilesByPatterns");
if (r < 0)
return bus_log_create_error(r);
m = sd_bus_message_unref(m);
sd_bus_error_free(&error);
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListUnitFiles");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFiles");
if (r < 0)
return bus_log_create_error(r);
if (arg_full)
table_set_width(table, 0);
+ (void) table_set_empty_string(table, "-");
+
for (m = machine_infos; m < machine_infos + n; m++) {
_cleanup_free_ char *mname = NULL;
const char *on_state = "", *on_failed = "";
return table_log_add_error(r);
}
- r = table_print(table, NULL);
+ r = output_table(table);
if (r < 0)
- return log_error_errno(r, "Failed to print the table: %m");
+ return r;
if (!arg_no_legend) {
printf("\n");
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetDefaultTarget",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, "GetDefaultTarget", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetDefaultTarget",
- &error,
- &reply,
- "sb", unit, 1);
+ r = bus_call_method(bus, bus_systemd_mgr, "SetDefaultTarget", &error, &reply, "sb", unit, 1);
if (r < 0)
return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
assert(bus);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method,
- &error,
- &reply,
- "u", id);
+ r = bus_call_method(bus, bus_systemd_mgr, method, &error, &reply, "u", id);
if (r < 0)
return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
if (arg_full)
table_set_width(table, 0);
+ (void) table_set_empty_string(table, "-");
+
for (j = jobs; j < jobs + n; j++) {
if (streq(j->state, "running"))
on = ansi_highlight();
else
on = "";
-
r = table_add_many(table,
TABLE_UINT, j->id,
TABLE_STRING, j->name,
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ListJobs",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, "ListJobs", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
if (q < 0)
return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
- q = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "CancelJob",
- &error,
- NULL,
- "u", id);
+ q = bus_call_method(bus, bus_systemd_mgr, "CancelJob", &error, NULL, "u", id);
if (q < 0) {
log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
if (r == 0)
/* We don't use unit_dbus_path_from_name() directly since we
* don't want to load the unit if it isn't loaded. */
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnit",
- NULL,
- &reply,
- "s", unit);
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnit", NULL, &reply, "s", unit);
if (r < 0)
return r;
_cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
/* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"EnqueueUnitJob",
&enqueue_error,
&reply,
}
if (!done) {
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method,
- error,
- &reply,
- "ss", name, mode);
+ r = bus_call_method(bus, bus_systemd_mgr, method, error, &reply, "ss", name, mode);
if (r < 0)
goto fail;
}
if (arg_wait) {
- r = sd_bus_call_method_async(
- bus,
- NULL,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Subscribe",
- NULL, NULL,
- NULL);
+ r = bus_call_method_async(bus, NULL, bus_systemd_mgr, "Subscribe", NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to enable subscription: %m");
if (arg_dry_run)
return 0;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
+ r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
if (r < 0)
return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
return 0;
if (arg_dry_run)
return 0;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- actions[a].method,
- &error,
- NULL,
- "b", arg_ask_password);
+ r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password);
if (r < 0)
return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ListInhibitors",
- NULL,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
if (r < 0)
/* If logind is not around, then there are no inhibitors... */
return 0;
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetRebootToFirmwareSetup",
- &error,
- NULL,
- "b", true);
+ r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
if (r < 0)
return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetRebootToBootLoaderMenu",
- &error,
- NULL,
- "t", arg_boot_loader_menu);
+ r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
if (r < 0)
return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetRebootToBootLoaderEntry",
- &error,
- NULL,
- "s", arg_boot_loader_entry);
+ r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
if (r < 0)
return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetExitCode",
- &error,
- NULL,
- "y", code);
+ r = bus_call_method(bus, bus_systemd_mgr, "SetExitCode", &error, NULL, "y", code);
if (r < 0)
return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- q = sd_bus_call_method(
+ q = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"KillUnit",
&error,
NULL,
return r;
}
-static int clean_unit(int argc, char *argv[], void *userdata) {
+static int clean_or_freeze_unit(int argc, char *argv[], void *userdata) {
_cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL;
_cleanup_strv_free_ char **names = NULL;
int r, ret = EXIT_SUCCESS;
char **name;
+ const char *method;
sd_bus *bus;
r = acquire_bus(BUS_FULL, &bus);
return log_error_errno(r, "Failed to allocate unit waiter: %m");
}
+ if (streq(argv[0], "clean"))
+ method = "CleanUnit";
+ else if (streq(argv[0], "freeze"))
+ method = "FreezeUnit";
+ else if (streq(argv[0], "thaw"))
+ method = "ThawUnit";
+ else
+ assert_not_reached("Unhandled method");
+
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
if (w) {
/* If we shall wait for the cleaning to complete, let's add a ref on the unit first */
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "RefUnit",
- &error,
- NULL,
- "s", *name);
+ r = bus_call_method(bus, bus_systemd_mgr, "RefUnit", &error, NULL, "s", *name);
if (r < 0) {
log_error_errno(r, "Failed to add reference to unit %s: %s", *name, bus_error_message(&error, r));
if (ret == EXIT_SUCCESS)
}
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "CleanUnit");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_strv(m, arg_clean_what);
- if (r < 0)
- return bus_log_create_error(r);
+ if (streq(method, "CleanUnit")) {
+ r = sd_bus_message_append_strv(m, arg_clean_what);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
r = sd_bus_call(bus, m, 0, &error, NULL);
if (r < 0) {
- log_error_errno(r, "Failed to clean unit %s: %s", *name, bus_error_message(&error, r));
+ log_error_errno(r, "Failed to %s unit %s: %s", argv[0], *name, bus_error_message(&error, r));
if (ret == EXIT_SUCCESS) {
ret = r;
continue;
const char *id;
const char *load_state;
const char *active_state;
+ const char *freezer_state;
const char *sub_state;
const char *unit_file_state;
const char *unit_file_preset;
bool *ellipsized) {
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
- const char *s1, *s2, *active_on, *active_off, *on, *off, *ss;
+ const char *s1, *s2, *active_on, *active_off, *on, *off, *ss, *fs;
_cleanup_free_ char *formatted_path = NULL;
ExecStatusInfo *p;
usec_t timestamp;
if (!isempty(i->load_error))
printf(" Loaded: %s%s%s (Reason: %s)\n",
on, strna(i->load_state), off, i->load_error);
- else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
- !STR_IN_SET(i->unit_file_state, "generated", "transient"))
- printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
- on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
- else if (path && !isempty(i->unit_file_state))
- printf(" Loaded: %s%s%s (%s; %s)\n",
- on, strna(i->load_state), off, path, i->unit_file_state);
- else if (path)
+ else if (path && !isempty(i->unit_file_state)) {
+ bool show_preset = !isempty(i->unit_file_preset) &&
+ show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
+
+ printf(" Loaded: %s%s%s (%s; %s%s%s)\n",
+ on, strna(i->load_state), off,
+ path,
+ i->unit_file_state,
+ show_preset ? "; vendor preset: " : "",
+ show_preset ? i->unit_file_preset : "");
+
+ } else if (path)
printf(" Loaded: %s%s%s (%s)\n",
on, strna(i->load_state), off, path);
else
printf(" Active: %s%s%s",
active_on, strna(i->active_state), active_off);
+ fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
+ if (fs)
+ printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
+
if (!isempty(i->result) && !streq(i->result, "success"))
printf(" (Result: %s)", i->result);
static const struct bus_properties_map property_map[] = {
{ "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
{ "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
+ { "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
{ "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
{}
}, status_map[] = {
{ "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
{ "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
{ "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
+ { "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
{ "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
{ "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
{ "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },
char *u;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnitByPID",
- &error,
- &reply,
- "u", pid);
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
if (r < 0)
return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "This command expects one or more unit names. Did you mean --help?");
+ "'help' command expects one or more unit names.\n"
+ "(Alternatively, help for systemctl itself may be shown with --help)");
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
polkit_agent_open_maybe();
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetUnitProperties");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetUnitProperties");
if (r < 0)
return bus_log_create_error(r);
assert_not_reached("Unexpected action");
}
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method);
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
if (r < 0)
return bus_log_create_error(r);
streq(argv[0], "exit") ? "Exit" :
/* poweroff */ "PowerOff";
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method,
- &error,
- NULL,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, method, &error, NULL, NULL);
if (r < 0 && arg_action == ACTION_SYSTEMCTL)
return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- q = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ResetFailedUnit",
- &error,
- NULL,
- "s", *name);
+ q = bus_call_method(bus, bus_systemd_mgr, "ResetFailedUnit", &error, NULL, "s", *name);
if (q < 0) {
log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
(void) pager_open(arg_pager_flags);
- r = sd_bus_get_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Environment",
- &error,
- &reply,
- "as");
+ r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
if (r < 0)
return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
log_debug("Switching root - root: %s; init: %s", root, strna(init));
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SwitchRoot",
- &error,
- NULL,
- "ss", root, init);
+ r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init);
if (r < 0) {
(void) default_signals(SIGTERM, -1);
if (argc == 1) {
_cleanup_free_ char *level = NULL;
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogLevel",
- &error,
- &level);
+ r = bus_get_property_string(bus, bus_systemd_mgr, "LogLevel", &error, &level);
if (r < 0)
return log_error_errno(r, "Failed to get log level: %s", bus_error_message(&error, r));
} else {
assert(argc == 2);
- r = sd_bus_set_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogLevel",
- &error,
- "s",
- argv[1]);
+ r = bus_set_property(bus, bus_systemd_mgr, "LogLevel", &error, "s", argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to set log level: %s", bus_error_message(&error, r));
}
if (argc == 1) {
_cleanup_free_ char *target = NULL;
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogTarget",
- &error,
- &target);
+ r = bus_get_property_string(bus, bus_systemd_mgr, "LogTarget", &error, &target);
if (r < 0)
return log_error_errno(r, "Failed to get log target: %s", bus_error_message(&error, r));
} else {
assert(argc == 2);
- r = sd_bus_set_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "LogTarget",
- &error,
- "s",
- argv[1]);
+ r = bus_set_property(bus, bus_systemd_mgr, "LogTarget", &error, "s", argv[1]);
if (r < 0)
return log_error_errno(r, "Failed to set log target: %s", bus_error_message(&error, r));
}
if (argc == 1) {
/* get ServiceWatchdogs */
- r = sd_bus_get_property_trivial(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ServiceWatchdogs",
- &error,
- 'b',
- &b);
+ r = bus_get_property_trivial(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, 'b', &b);
if (r < 0)
return log_error_errno(r, "Failed to get service-watchdog state: %s", bus_error_message(&error, r));
if (b < 0)
return log_error_errno(b, "Failed to parse service-watchdogs argument: %m");
- r = sd_bus_set_property(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "ServiceWatchdogs",
- &error,
- "b",
- b);
+ r = bus_set_property(bus, bus_systemd_mgr, "ServiceWatchdogs", &error, "b", b);
if (r < 0)
return log_error_errno(r, "Failed to set service-watchdog state: %s", bus_error_message(&error, r));
}
? "SetEnvironment"
: "UnsetEnvironment";
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method);
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_maybe();
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetEnvironment");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
if (r < 0)
return bus_log_create_error(r);
} else
assert_not_reached("Unknown verb");
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method);
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_maybe();
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "AddDependencyUnitFiles");
+ r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "AddDependencyUnitFiles");
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_maybe();
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"PresetAllUnitFiles",
&error,
&reply,
const char *link;
int r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnitFileLinks",
- &error,
- &reply,
- "sb", name, arg_runtime);
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileLinks", &error, &reply, "sb", name, arg_runtime);
if (r < 0)
return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
UNIT_FILE_ENABLED,
UNIT_FILE_ENABLED_RUNTIME,
UNIT_FILE_STATIC,
+ UNIT_FILE_ALIAS,
UNIT_FILE_INDIRECT,
UNIT_FILE_GENERATED))
enabled = true;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *s;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "GetUnitFileState",
- &error,
- &reply,
- "s", *name);
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", *name);
if (r < 0)
return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
assert(state);
- r = sd_bus_get_property_string(
- sd_bus_message_get_bus(m),
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SystemState",
- NULL,
- state);
+ r = bus_get_property_string(sd_bus_message_get_bus(m), bus_systemd_mgr, "SystemState", NULL, state);
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), r);
return 0;
if (r >= 0)
r = sd_bus_attach_event(bus, event, 0);
if (r >= 0)
- r = sd_bus_match_signal_async(
+ r = bus_match_signal_async(
bus,
&slot_startup_finished,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"StartupFinished",
match_startup_finished, NULL, &state);
if (r < 0) {
}
}
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SystemState",
- &error,
- &state);
+ r = bus_get_property_string(bus, bus_systemd_mgr, "SystemState", &error, &state);
if (r < 0) {
log_warning_errno(r, "Failed to query system state: %s", bus_error_message(&error, r));
" kill UNIT... Send signal to processes of a unit\n"
" clean UNIT... Clean runtime, cache, state, logs or\n"
" configuration of unit\n"
+ " freeze PATTERN... Freeze execution of unit processes\n"
+ " thaw PATTERN... Resume execution of a frozen unit\n"
" is-active PATTERN... Check whether units are active\n"
" is-failed PATTERN... Check whether units are failed\n"
" status [PATTERN...|PID...] Show runtime status of one or more units\n"
if (r < 0)
return r;
- r = sd_bus_get_property_strv(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "BootLoaderEntries",
- &error,
- &l);
+ r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
if (r < 0)
return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown output '%s'.",
optarg);
+
+ if (OUTPUT_MODE_IS_JSON(arg_output)) {
+ arg_no_legend = true;
+ arg_plain = true;
+ }
break;
case 'i':
{ "condrestart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with RH */
{ "isolate", 2, 2, VERB_ONLINE_ONLY, start_unit },
{ "kill", 2, VERB_ANY, VERB_ONLINE_ONLY, kill_unit },
- { "clean", 2, VERB_ANY, VERB_ONLINE_ONLY, clean_unit },
+ { "clean", 2, VERB_ANY, VERB_ONLINE_ONLY, clean_or_freeze_unit },
+ { "freeze", 2, VERB_ANY, VERB_ONLINE_ONLY, clean_or_freeze_unit },
+ { "thaw", 2, VERB_ANY, VERB_ONLINE_ONLY, clean_or_freeze_unit },
{ "is-active", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active },
{ "check", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active }, /* deprecated alias of is-active */
{ "is-failed", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_failed },
{ "help", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
{ "daemon-reload", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
{ "daemon-reexec", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
- { "log-level", VERB_ANY, 2, 0, log_level },
- { "log-target", VERB_ANY, 2, 0, log_target },
- { "service-watchdogs", VERB_ANY, 2, 0, service_watchdogs },
+ { "log-level", VERB_ANY, 2, VERB_ONLINE_ONLY, log_level },
+ { "log-target", VERB_ANY, 2, VERB_ONLINE_ONLY, log_target },
+ { "service-watchdogs", VERB_ANY, 2, VERB_ONLINE_ONLY, service_watchdogs },
{ "show-environment", VERB_ANY, 1, VERB_ONLINE_ONLY, show_environment },
{ "set-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },
{ "unset-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },
{}
};
+ const Verb *verb = verbs_find_verb(argv[optind], verbs);
+ if (verb && (verb->flags & VERB_ONLINE_ONLY) && arg_root)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Verb '%s' cannot be used with --root=.",
+ argv[optind] ?: verb->verb);
+
return dispatch_verb(argc, argv, verbs, NULL);
}
(void) logind_set_wall_message();
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ScheduleShutdown",
- &error,
- NULL,
- "st",
- action,
- arg_when);
+ r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
if (r < 0)
return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
(void) logind_set_wall_message();
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CancelScheduledShutdown",
- &error,
- NULL, NULL);
+ r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
if (r < 0)
return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION = 1ULL << 6,
SD_BUS_VTABLE_PROPERTY_EXPLICIT = 1ULL << 7,
SD_BUS_VTABLE_SENSITIVE = 1ULL << 8, /* covers both directions: method call + reply */
+ SD_BUS_VTABLE_ABSOLUTE_OFFSET = 1ULL << 9,
_SD_BUS_VTABLE_CAPABILITY_MASK = 0xFFFFULL << 40
};
.x = { { 0 } }, \
}
+#define _SD_ECHO(X) X
+#define _SD_CONCAT(X) #X "\0"
+
+#define _SD_VARARGS_FOREACH_EVEN_01(FN, X, ...)
+#define _SD_VARARGS_FOREACH_EVEN_02(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_01(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_03(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_02(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_04(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_03(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_05(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_04(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_06(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_05(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_07(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_06(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_08(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_07(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_09(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_08(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_10(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_09(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_11(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_10(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_12(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_11(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_13(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_12(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_14(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_13(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_15(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_14(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_16(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_15(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_17(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_16(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_18(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_17(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_19(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_18(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_20(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_19(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_21(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_20(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_22(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_21(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_23(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_22(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_24(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_23(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_25(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_24(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_26(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_25(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_27(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_26(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_28(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_27(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_29(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_28(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_30(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_29(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_31(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_30(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_32(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_31(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_33(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_32(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_34(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_33(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_35(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_34(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_36(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_35(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_37(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_36(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_38(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_37(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_39(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_38(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_40(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_39(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_41(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_40(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_42(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_41(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_43(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_42(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_44(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_43(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_45(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_44(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_46(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_45(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_47(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_46(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_48(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_47(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_49(FN, X, ...) _SD_VARARGS_FOREACH_EVEN_48(FN, __VA_ARGS__)
+#define _SD_VARARGS_FOREACH_EVEN_50(FN, X, ...) FN(X) _SD_VARARGS_FOREACH_EVEN_49(FN, __VA_ARGS__)
+
+#define _SD_VARARGS_FOREACH_EVEN_SEQ(_01, _02, _03, _04, _05, _06, _07, _08, _09, _10, \
+ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
+ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
+ _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
+ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
+ NAME, ...) NAME
+
+#define _SD_VARARGS_FOREACH_EVEN(FN, ...) \
+ _SD_VARARGS_FOREACH_EVEN_SEQ(__VA_ARGS__, \
+ _SD_VARARGS_FOREACH_EVEN_50, _SD_VARARGS_FOREACH_EVEN_49, \
+ _SD_VARARGS_FOREACH_EVEN_48, _SD_VARARGS_FOREACH_EVEN_47, \
+ _SD_VARARGS_FOREACH_EVEN_46, _SD_VARARGS_FOREACH_EVEN_45, \
+ _SD_VARARGS_FOREACH_EVEN_44, _SD_VARARGS_FOREACH_EVEN_43, \
+ _SD_VARARGS_FOREACH_EVEN_42, _SD_VARARGS_FOREACH_EVEN_41, \
+ _SD_VARARGS_FOREACH_EVEN_40, _SD_VARARGS_FOREACH_EVEN_39, \
+ _SD_VARARGS_FOREACH_EVEN_38, _SD_VARARGS_FOREACH_EVEN_37, \
+ _SD_VARARGS_FOREACH_EVEN_36, _SD_VARARGS_FOREACH_EVEN_35, \
+ _SD_VARARGS_FOREACH_EVEN_34, _SD_VARARGS_FOREACH_EVEN_33, \
+ _SD_VARARGS_FOREACH_EVEN_32, _SD_VARARGS_FOREACH_EVEN_31, \
+ _SD_VARARGS_FOREACH_EVEN_30, _SD_VARARGS_FOREACH_EVEN_29, \
+ _SD_VARARGS_FOREACH_EVEN_28, _SD_VARARGS_FOREACH_EVEN_27, \
+ _SD_VARARGS_FOREACH_EVEN_26, _SD_VARARGS_FOREACH_EVEN_25, \
+ _SD_VARARGS_FOREACH_EVEN_24, _SD_VARARGS_FOREACH_EVEN_23, \
+ _SD_VARARGS_FOREACH_EVEN_22, _SD_VARARGS_FOREACH_EVEN_21, \
+ _SD_VARARGS_FOREACH_EVEN_20, _SD_VARARGS_FOREACH_EVEN_19, \
+ _SD_VARARGS_FOREACH_EVEN_18, _SD_VARARGS_FOREACH_EVEN_17, \
+ _SD_VARARGS_FOREACH_EVEN_16, _SD_VARARGS_FOREACH_EVEN_15, \
+ _SD_VARARGS_FOREACH_EVEN_14, _SD_VARARGS_FOREACH_EVEN_13, \
+ _SD_VARARGS_FOREACH_EVEN_12, _SD_VARARGS_FOREACH_EVEN_11, \
+ _SD_VARARGS_FOREACH_EVEN_10, _SD_VARARGS_FOREACH_EVEN_09, \
+ _SD_VARARGS_FOREACH_EVEN_08, _SD_VARARGS_FOREACH_EVEN_07, \
+ _SD_VARARGS_FOREACH_EVEN_06, _SD_VARARGS_FOREACH_EVEN_05, \
+ _SD_VARARGS_FOREACH_EVEN_04, _SD_VARARGS_FOREACH_EVEN_03, \
+ _SD_VARARGS_FOREACH_EVEN_02, _SD_VARARGS_FOREACH_EVEN_01) \
+ (FN, __VA_ARGS__)
+
+#define SD_BUS_ARGS(...) __VA_ARGS__
+#define SD_BUS_RESULT(...) __VA_ARGS__
+
+#define SD_BUS_NO_ARGS SD_BUS_ARGS(NULL,)
+#define SD_BUS_NO_RESULT SD_BUS_RESULT(NULL,)
+
+#define SD_BUS_METHOD_WITH_ARGS(_member, _args, _result, _handler, _flags) \
+ SD_BUS_METHOD_WITH_NAMES(_member, \
+ _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _args), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _args, ""), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _result), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _result, ""), \
+ _handler, _flags)
+
+#define SD_BUS_METHOD_WITH_ARGS_OFFSET(_member, _args, _result, _handler, _offset, _flags) \
+ SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, \
+ _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _args), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _args, ""), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _result), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _result, ""), \
+ _handler, _offset, _flags)
+
+#define SD_BUS_SIGNAL_WITH_ARGS(_member, _args, _flags) \
+ SD_BUS_SIGNAL_WITH_NAMES(_member, \
+ _SD_VARARGS_FOREACH_EVEN(_SD_ECHO, _args), \
+ _SD_VARARGS_FOREACH_EVEN(_SD_CONCAT, _args, ""), \
+ _flags)
+
_SD_END_DECLARATIONS;
#endif
int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces);
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
-int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
-int sd_bus_query_sender_privilege(sd_bus_message *call, int capability);
+int sd_bus_query_sender_creds(sd_bus_message *m, uint64_t mask, sd_bus_creds **creds);
+int sd_bus_query_sender_privilege(sd_bus_message *m, int capability);
int sd_bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata);
int sd_bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t match_callback, sd_bus_message_handler_t add_callback, void *userdata);
*/
int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds);
+/*
+ Returns > 0 if synchronization with systemd succeeded. Returns < 0
+ on error. Returns 0 if $NOTIFY_SOCKET was not set. Note that the
+ timeout parameter of this function call takes the timeout in µs, and
+ will be passed to ppoll(2), hence the behaviour will be similar to
+ ppoll(2). This function can be called after sending a status message
+ to systemd, if one needs to synchronize against reception of the
+ status messages sent before this call is made. Therefore, this
+ cannot be used to know if the status message was processed
+ successfully, but to only synchronize against its consumption.
+*/
+int sd_notify_barrier(int unset_environment, uint64_t timeout);
+
/*
Returns > 0 if the system was booted with systemd. Returns < 0 on
error. Returns 0 if the system was not booted with systemd. Note
int sd_dhcp_client_set_service_type(
sd_dhcp_client *client,
int type);
+int sd_dhcp_client_set_fallback_lease_lifetime(
+ sd_dhcp_client *client,
+ uint32_t fallback_lease_lifetime);
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_server_start(sd_dhcp_server *server);
int sd_dhcp_server_stop(sd_dhcp_server *server);
-int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size);
+int sd_dhcp_server_configure_pool(sd_dhcp_server *server, const struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size);
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
sd_dhcp_server *server,
sd_dhcp_lease_info what,
const struct in_addr addresses[],
- unsigned n_addresses);
-
-int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], unsigned n);
-int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n);
-int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n);
-int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], unsigned n);
-int sd_dhcp_server_set_pop3_server(sd_dhcp_server *server, const struct in_addr pop3_server[], unsigned n);
-int sd_dhcp_server_set_smtp_server(sd_dhcp_server *server, const struct in_addr smtp_server[], unsigned n);
+ size_t n_addresses);
+
+int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n);
+int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n);
+int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n);
+int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n);
+int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3_server[], size_t n);
+int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp_server[], size_t n);
int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v);
int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v);
#include <sys/types.h>
#include "sd-dhcp6-lease.h"
+#include "sd-dhcp6-option.h"
#include "sd-event.h"
#include "_sd-common.h"
uint16_t option);
int sd_dhcp6_client_set_request_mud_url(
sd_dhcp6_client *client,
- char *mudurl);
+ const char *mudurl);
+int sd_dhcp6_client_set_request_user_class(
+ sd_dhcp6_client *client,
+ char** user_class);
+int sd_dhcp6_client_set_request_vendor_class(
+ sd_dhcp6_client *client,
+ char** vendor_class);
int sd_dhcp6_client_set_prefix_delegation_hint(
sd_dhcp6_client *client,
uint8_t prefixlen,
sd_dhcp6_client *client,
sd_dhcp6_lease **ret);
+int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v);
+
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#ifndef foosddhcp6optionhfoo
+#define foosddhcp6optionhfoo
+
+/***
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_dhcp6_option sd_dhcp6_option;
+
+int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, sd_dhcp6_option **ret);
+sd_dhcp6_option *sd_dhcp6_option_ref(sd_dhcp6_option *ra);
+sd_dhcp6_option *sd_dhcp6_option_unref(sd_dhcp6_option *ra);
+
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_option, sd_dhcp6_option_unref);
+
+_SD_END_DECLARATIONS;
+
+#endif
ORDERED_HASHMAP_FOREACH(i, todo_uids, iterator) {
struct spwd n = {
.sp_namp = i->name,
- .sp_pwdp = (char*) "!!", /* lock this password, and make it invalid */
+ .sp_pwdp = (char*) "!*", /* lock this password, and make it invalid */
.sp_lstchg = lstchg,
.sp_min = -1,
.sp_max = -1,
static int parse_line(const char *fname, unsigned line, const char *buffer) {
static const Specifier specifier_table[] = {
- { 'm', specifier_machine_id, NULL },
- { 'b', specifier_boot_id, NULL },
- { 'H', specifier_host_name, NULL },
- { 'v', specifier_kernel_release, NULL },
- { 'T', specifier_tmp_dir, NULL },
- { 'V', specifier_var_tmp_dir, NULL },
+ { 'm', specifier_machine_id, NULL },
+ { 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
+ { 'l', specifier_short_host_name, NULL },
+ { 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
+ { 'T', specifier_tmp_dir, NULL },
+ { 'V', specifier_var_tmp_dir, NULL },
{}
};
if (name) {
r = specifier_printf(name, specifier_table, NULL, &resolved_name);
if (r < 0)
- log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, name);
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name);
if (!valid_user_group_name(resolved_name, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
if (id) {
r = specifier_printf(id, specifier_table, NULL, &resolved_id);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, name);
}
if (description) {
r = specifier_printf(description, specifier_table, NULL, &resolved_description);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, description);
if (!valid_gecos(resolved_description))
if (home) {
r = specifier_printf(home, specifier_table, NULL, &resolved_home);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, home);
if (!valid_home(resolved_home))
if (shell) {
r = specifier_printf(shell, specifier_table, NULL, &resolved_shell);
if (r < 0)
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+ return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m",
fname, line, shell);
if (!valid_shell(resolved_shell))
break;
case ARG_ROOT:
- r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;
'', 'timeout=90'],
[['src/test/test-set.c'],
- [],
+ [libbasic],
[]],
[['src/test/test-ordered-set.c'],
[libjournal_core,
libshared],
[liblz4,
+ libzstd,
libxz]],
[['src/journal/test-compress-benchmark.c'],
[libjournal_core,
libshared],
[liblz4,
+ libzstd,
libxz],
'', 'timeout=90'],
g = cp; /* cast from pointer */
h = NULL; /* cast from pointer */
- assert(b);
- assert(c);
- assert(d);
- assert(e);
- assert(!f);
- assert(g);
- assert(!h);
+ assert_se(b);
+ assert_se(c);
+ assert_se(d);
+ assert_se(e);
+ assert_se(!f);
+ assert_se(g);
+ assert_se(!h);
}
static int cleanup_counter = 0;
r = acpi_get_boot_usec(&loader_start, &loader_exit);
if (r < 0) {
- bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA;
+ bool ok = r == -ENOENT || r == -EACCES || r == -ENODATA;
log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read ACPI FPDT: %m");
return ok ? 0 : r;
r = efi_loader_get_boot_usec(&loader_start, &loader_exit);
if (r < 0) {
- bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -EOPNOTSUPP;
+ bool ok = r == -ENOENT || r == -EACCES || r == -EOPNOTSUPP;
log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read EFI loader data: %m");
return ok ? 0 : r;
r = boot_timestamps(NULL, &fw, &l);
if (r < 0) {
- bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -EOPNOTSUPP;
+ bool ok = r == -ENOENT || r == -EACCES || r == -EOPNOTSUPP;
log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read variables: %m");
return ok ? 0 : r;
test_one("@1493187147 UTC", "2017-04-26 06:12:27 UTC");
test_one("@0", "1970-01-01 00:00:00 UTC");
test_one("@0 UTC", "1970-01-01 00:00:00 UTC");
+ test_one("*:05..05", "*-*-* *:05:00");
+ test_one("*:05..10/6", "*-*-* *:05:00");
test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
assert_se(calendar_spec_from_string("*~29", &c) < 0);
assert_se(calendar_spec_from_string("*~16..31", &c) < 0);
assert_se(calendar_spec_from_string("12..1/2-*", &c) < 0);
- assert_se(calendar_spec_from_string("*:05..05", &c) < 0);
- assert_se(calendar_spec_from_string("*:05..10/6", &c) < 0);
assert_se(calendar_spec_from_string("20/4:00", &c) < 0);
assert_se(calendar_spec_from_string("00:00/60", &c) < 0);
assert_se(calendar_spec_from_string("00:00:2300", &c) < 0);
#include "alloc-util.h"
#include "capability-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "macro.h"
int r;
r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
+ if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* kernel pre 3.2 or no access */
+ return;
assert_se(r >= 0);
r = safe_atolu(content, &val);
int r;
r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
- if (r == -ENOENT) /* kernel pre 3.2 */
+ if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* kernel pre 3.2 or no access */
return;
assert_se(r >= 0);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <unistd.h>
+
#include "alloc-util.h"
#include "build.h"
#include "cgroup-setup.h"
+#include "errno-util.h"
#include "log.h"
#include "proc-cmdline.h"
#include "string-util.h"
int main(void) {
test_setup_logging(LOG_DEBUG);
+ if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return log_tests_skipped("can't read /proc/cmdline");
+
test_is_wanted_print(true);
test_is_wanted_print(false); /* run twice to test caching */
test_is_wanted();
#include "build.h"
#include "cgroup-util.h"
#include "dirent-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "parse-util.h"
int i, r;
r = cg_get_keyed_attribute("cpu", "/init.scope", "no_such_file", STRV_MAKE("no_such_attr"), &val);
- if (r == -ENOMEDIUM) {
+ if (r == -ENOMEDIUM || ERRNO_IS_PRIVILEGE(r)) {
log_info_errno(r, "Skipping most of %s, /sys/fs/cgroup not accessible: %m", __func__);
return;
}
}
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == -ENXIO);
+ assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == 0);
assert_se(val == NULL);
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 0);
+ val = mfree(val);
+
+ assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 1);
log_info("cpu /init.scope cpu.stat [usage_usec] → \"%s\"", val);
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == -ENXIO);
+ assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == 1);
+ assert(vals3[0] && !vals3[1]);
+ free(vals3[0]);
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == -ENXIO);
+ assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == 1);
+ assert(vals3[0] && !vals3[1]);
+ free(vals3[0]);
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0);
+ for (i = 0; i < 3; i++)
+ free(vals3[i]);
+
+ assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
+ STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 3);
log_info("cpu /init.scope cpu.stat [usage_usec user_usec system_usec] → \"%s\", \"%s\", \"%s\"",
vals3[0], vals3[1], vals3[2]);
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0);
+ for (i = 0; i < 3; i++)
+ free(vals3a[i]);
+
+ assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
+ STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 3);
log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"",
vals3a[0], vals3a[1], vals3a[2]);
static void test_cg_create(void) {
log_info("/* %s */", __func__);
+ int r;
+
+ r = cg_unified_cached(false);
+ if (r < 0) {
+ log_info_errno(r, "Skipping %s: %m", __func__);
+ return;
+ }
_cleanup_free_ char *here = NULL;
assert_se(cg_pid_get_path_shifted(0, NULL, &here) >= 0);
*test_c = prefix_roota(here, "/test-b/test-c"),
*test_d = prefix_roota(here, "/test-b/test-d");
char *path;
- int r;
log_info("Paths for test:\n%s\n%s", test_a, test_b);
int r;
r = clock_is_localtime(NULL);
- if (access("/etc/adjtime", F_OK) == 0) {
- log_info("/etc/adjtime exists, clock_is_localtime() == %i", r);
+ if (access("/etc/adjtime", R_OK) == 0) {
+ log_info("/etc/adjtime is readable, clock_is_localtime() == %i", r);
/* if /etc/adjtime exists we expect some answer, no error or
* crash */
assert_se(IN_SET(r, 0, 1));
} else
/* default is UTC if there is no /etc/adjtime */
- assert_se(r == 0);
+ assert_se(r == 0 || ERRNO_IS_PRIVILEGE(r));
}
int main(int argc, char *argv[]) {
#include "condition.h"
#include "cpu-set-util.h"
#include "efi-loader.h"
+#include "errno-util.h"
#include "hostname-util.h"
#include "id128-util.h"
#include "ima-util.h"
condition = condition_new(CONDITION_PATH_EXISTS, "/bin/sh", false, false);
assert_se(condition);
- assert_se(condition_test(condition));
+ assert_se(condition_test(condition, environ));
condition_free(condition);
condition = condition_new(CONDITION_PATH_EXISTS, "/bin/s?", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, true);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_IS_DIRECTORY, "/bin", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_DIRECTORY_NOT_EMPTY, "/bin", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_FILE_NOT_EMPTY, "/bin/sh", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/bin/sh", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/etc/passwd", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/proc", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/bin", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_IS_READ_WRITE, "/tmp", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_IS_ENCRYPTED, "/sys", false, false);
+ assert_se(condition);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
}
/* Invalid controllers are ignored */
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
assert_se(cg_mask_supported(&system_mask) >= 0);
log_info("this controller is available");
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
} else {
log_info("this controller is unavailable");
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, local_controller_name, false, true);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
}
}
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, strempty(controller_name), false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
}
condition = condition_new(CONDITION_AC_POWER, "true", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == on_ac_power());
+ assert_se(condition_test(condition, environ) == on_ac_power());
condition_free(condition);
condition = condition_new(CONDITION_AC_POWER, "false", false, false);
assert_se(condition);
- assert_se(condition_test(condition) != on_ac_power());
+ assert_se(condition_test(condition, environ) != on_ac_power());
condition_free(condition);
condition = condition_new(CONDITION_AC_POWER, "false", false, true);
assert_se(condition);
- assert_se(condition_test(condition) == on_ac_power());
+ assert_se(condition_test(condition, environ) == on_ac_power());
condition_free(condition);
}
condition = condition_new(CONDITION_HOST, sid, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_HOST, sid, false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
hostname = gethostname_malloc();
else {
condition = condition_new(CONDITION_HOST, hostname, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
}
}
condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
}
static void test_condition_test_kernel_command_line(void) {
Condition *condition;
+ int r;
condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "thisreallyshouldntbeonthekernelcommandline", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ r = condition_test(condition, environ);
+ if (ERRNO_IS_PRIVILEGE(r))
+ return;
+ assert_se(r == 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "andthis=neither", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
}
condition = condition_new(CONDITION_KERNEL_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "*", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
/* An artificially empty condition. It evaluates to true, but normally
* such condition cannot be created, because the condition list is reset instead. */
condition = condition_new(CONDITION_KERNEL_VERSION, "", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
assert_se(uname(&u) >= 0);
condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
strshorten(u.release, 4);
condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
/* 0.1.2 would be a very very very old kernel */
condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, ">0.1.2", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "'>0.1.2' '<9.0.0'", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2 < 9.0.0", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == -EINVAL);
+ assert_se(condition_test(condition, environ) == -EINVAL);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, ">", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == -EINVAL);
+ assert_se(condition_test(condition, environ) == -EINVAL);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, ">= 0.1.2", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "< 0.1.2", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "<= 0.1.2", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "= 0.1.2", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
/* 4711.8.15 is a very very very future kernel */
condition = condition_new(CONDITION_KERNEL_VERSION, "< 4711.8.15", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "<= 4711.8.15", false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "= 4711.8.15", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, "> 4711.8.15", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_KERNEL_VERSION, ">= 4711.8.15", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
assert_se(uname(&u) >= 0);
v = strjoina(">=", u.release);
condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
v = strjoina("= ", u.release);
condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
v = strjoina("<=", u.release);
condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
v = strjoina("> ", u.release);
condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
v = strjoina("< ", u.release);
condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
}
condition = condition_new(CONDITION_NULL, NULL, false, false);
assert_se(condition);
- assert_se(condition_test(condition) > 0);
+ assert_se(condition_test(condition, environ) > 0);
condition_free(condition);
condition = condition_new(CONDITION_NULL, NULL, false, true);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
}
condition = condition_new(CONDITION_SECURITY, "garbage oifdsjfoidsjoj", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == 0);
+ assert_se(condition_test(condition, environ) == 0);
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "selinux", false, true);
assert_se(condition);
- assert_se(condition_test(condition) != mac_selinux_use());
+ assert_se(condition_test(condition, environ) != mac_selinux_use());
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "apparmor", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == mac_apparmor_use());
+ assert_se(condition_test(condition, environ) == mac_apparmor_use());
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "tomoyo", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == mac_tomoyo_use());
+ assert_se(condition_test(condition, environ) == mac_tomoyo_use());
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "ima", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == use_ima());
+ assert_se(condition_test(condition, environ) == use_ima());
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "smack", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == mac_smack_use());
+ assert_se(condition_test(condition, environ) == mac_smack_use());
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "audit", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == use_audit());
+ assert_se(condition_test(condition, environ) == use_audit());
condition_free(condition);
condition = condition_new(CONDITION_SECURITY, "uefi-secureboot", false, false);
assert_se(condition);
- assert_se(condition_test(condition) == is_efi_secure_boot());
+ assert_se(condition_test(condition, environ) == is_efi_secure_boot());
condition_free(condition);
}
condition = condition_new(CONDITION_VIRTUALIZATION, "garbage oifdsjfoidsjoj", false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
+ if (ERRNO_IS_PRIVILEGE(r))
+ return;
log_info("ConditionVirtualization=garbage → %i", r);
assert_se(r == 0);
condition_free(condition);
condition = condition_new(CONDITION_VIRTUALIZATION, "container", false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionVirtualization=container → %i", r);
assert_se(r == !!detect_container());
condition_free(condition);
condition = condition_new(CONDITION_VIRTUALIZATION, "vm", false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionVirtualization=vm → %i", r);
assert_se(r == (detect_vm() && !detect_container()));
condition_free(condition);
condition = condition_new(CONDITION_VIRTUALIZATION, "private-users", false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionVirtualization=private-users → %i", r);
assert_se(r == !!running_in_userns());
condition_free(condition);
condition = condition_new(CONDITION_VIRTUALIZATION, virt, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionVirtualization=%s → %i", virt, r);
assert_se(r >= 0);
condition_free(condition);
condition = condition_new(CONDITION_USER, "garbage oifdsjfoidsjoj", false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=garbage → %i", r);
assert_se(r == 0);
condition_free(condition);
assert_se(asprintf(&uid, "%"PRIu32, UINT32_C(0xFFFF)) > 0);
condition = condition_new(CONDITION_USER, uid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=%s → %i", uid, r);
assert_se(r == 0);
condition_free(condition);
assert_se(asprintf(&uid, "%u", (unsigned)getuid()) > 0);
condition = condition_new(CONDITION_USER, uid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=%s → %i", uid, r);
assert_se(r > 0);
condition_free(condition);
assert_se(asprintf(&uid, "%u", (unsigned)getuid()+1) > 0);
condition = condition_new(CONDITION_USER, uid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=%s → %i", uid, r);
assert_se(r == 0);
condition_free(condition);
assert_se(username);
condition = condition_new(CONDITION_USER, username, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=%s → %i", username, r);
assert_se(r > 0);
condition_free(condition);
username = (char*)(geteuid() == 0 ? NOBODY_USER_NAME : "root");
condition = condition_new(CONDITION_USER, username, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=%s → %i", username, r);
assert_se(r == 0);
condition_free(condition);
condition = condition_new(CONDITION_USER, "@system", false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionUser=@system → %i", r);
if (uid_is_system(getuid()) || uid_is_system(geteuid()))
assert_se(r > 0);
assert_se(0 < asprintf(&gid, "%u", UINT32_C(0xFFFF)));
condition = condition_new(CONDITION_GROUP, gid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionGroup=%s → %i", gid, r);
assert_se(r == 0);
condition_free(condition);
assert_se(0 < asprintf(&gid, "%u", getgid()));
condition = condition_new(CONDITION_GROUP, gid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionGroup=%s → %i", gid, r);
assert_se(r > 0);
condition_free(condition);
assert_se(0 < asprintf(&gid, "%u", gids[i]));
condition = condition_new(CONDITION_GROUP, gid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionGroup=%s → %i", gid, r);
assert_se(r > 0);
condition_free(condition);
assert_se(groupname);
condition = condition_new(CONDITION_GROUP, groupname, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionGroup=%s → %i", groupname, r);
assert_se(r > 0);
condition_free(condition);
assert_se(0 < asprintf(&gid, "%u", max_gid+1));
condition = condition_new(CONDITION_GROUP, gid, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionGroup=%s → %i", gid, r);
assert_se(r == 0);
condition_free(condition);
groupname = (char*)(getegid() == 0 ? NOBODY_GROUP_NAME : "root");
condition = condition_new(CONDITION_GROUP, groupname, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
log_info("ConditionGroup=%s → %i", groupname, r);
assert_se(r == 0);
condition_free(condition);
condition = condition_new(CONDITION_CPUS, s, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
assert_se(r >= 0);
assert_se(r == result);
condition_free(condition);
condition = condition_new(CONDITION_MEMORY, s, false, false);
assert_se(condition);
- r = condition_test(condition);
+ r = condition_test(condition, environ);
assert_se(r >= 0);
assert_se(r == result);
condition_free(condition);
t = mfree(t);
}
+static void test_condition_test_environment_one(const char *s, bool result) {
+ Condition *condition;
+ int r;
+
+ log_debug("%s=%s", condition_type_to_string(CONDITION_ENVIRONMENT), s);
+
+ condition = condition_new(CONDITION_ENVIRONMENT, s, false, false);
+ assert_se(condition);
+
+ r = condition_test(condition, environ);
+ assert_se(r >= 0);
+ assert_se(r == result);
+ condition_free(condition);
+}
+
+static void test_condition_test_environment(void) {
+ assert_se(setenv("EXISTINGENVVAR", "foo", false) >= 0);
+
+ test_condition_test_environment_one("MISSINGENVVAR", false);
+ test_condition_test_environment_one("MISSINGENVVAR=foo", false);
+ test_condition_test_environment_one("MISSINGENVVAR=", false);
+
+ test_condition_test_environment_one("EXISTINGENVVAR", true);
+ test_condition_test_environment_one("EXISTINGENVVAR=foo", true);
+ test_condition_test_environment_one("EXISTINGENVVAR=bar", false);
+ test_condition_test_environment_one("EXISTINGENVVAR=", false);
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_condition_test_control_group_controller();
test_condition_test_cpus();
test_condition_test_memory();
+ test_condition_test_environment();
return 0;
}
}
static void test_copy_tree(void) {
- char original_dir[] = "/var/tmp/test-copy_tree/";
- char copy_dir[] = "/var/tmp/test-copy_tree-copy/";
+ char original_dir[] = "/tmp/test-copy_tree/";
+ char copy_dir[] = "/tmp/test-copy_tree-copy/";
char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
char **links = STRV_MAKE("link", "file",
"link2", "dir1/file");
q = strjoina(p, "/fstab");
r = copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REFLINK);
- if (r == -ENOENT)
+ if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
return;
assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REFLINK) == -EEXIST);
assert_se(chmod(masked2e, 0755) == 0);
assert_se(chmod(mask2e, 0755) == 0);
+ if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return;
+
if (gather_stdout)
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
else
assert_se(chmod(override, 0755) == 0);
assert_se(chmod(masked, 0755) == 0);
+ if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return;
+
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
assert_se(read_full_file(output, &contents, NULL) >= 0);
assert_se(chmod(name2, 0755) == 0);
assert_se(chmod(name3, 0755) == 0);
+ if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return;
+
r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
assert_se(r >= 0);
r = setenv("PATH", "no-sh-built-in-path", 1);
assert_se(r >= 0);
+ if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return;
+
r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
assert_se(r >= 0);
assert_se(chmod(name2, 0755) == 0);
assert_se(chmod(name3, 0755) == 0);
+ if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return;
+
r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL, EXEC_DIR_NONE);
/* we should exit with the error code of the first script that failed */
(void) unsetenv("LOGNAME");
(void) unsetenv("SHELL");
(void) unsetenv("HOME");
+ (void) unsetenv("TMPDIR");
can_unshare = have_namespaces();
ssize_t x, y;
x = read(fd1, a, sizeof(a));
- assert(x >= 0);
+ assert_se(x >= 0);
y = read(fd2, b, sizeof(b));
- assert(y >= 0);
+ assert_se(y >= 0);
- assert(x == y);
+ assert_se(x == y);
if (x == 0)
break;
- assert(memcmp(a, b, x) == 0);
+ assert_se(memcmp(a, b, x) == 0);
}
}
_cleanup_free_ char *buf = NULL, *buf2 = NULL;
int r;
- assert_se(read_one_line_file("/proc/version", &buf) >= 0);
+ r = read_one_line_file("/proc/version", &buf);
+ if (ERRNO_IS_PRIVILEGE(r))
+ return;
+ assert_se(r >= 0);
assert_se(buf2 = strjoin(buf, "\n"));
r = write_string_file("/proc/version", buf, 0);
assert_se(st.st_blocks > 0);
assert_se(st.st_nlink == 1);
- assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0);
+ assert_se(unlinkat_deallocate(AT_FDCWD, p, UNLINK_ERASE) >= 0);
assert_se(fstat(fd, &st) >= 0);
assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6
assert_se(S_ISLNK(st.st_mode));
}
+static void test_path_is_encrypted_one(const char *p, int expect) {
+ int r;
+
+ r = path_is_encrypted(p);
+ if (r == -ENOENT) /* This might fail, if btrfs is used and we run in a container. In that case we
+ * cannot resolve the device node paths that BTRFS_IOC_DEV_INFO returns, because
+ * the device nodes are unlikely to exist in the container. But if we can't stat()
+ * them we cannot determine the dev_t of them, and thus cannot figure out if they
+ * are enrypted. Hence let's just ignore ENOENT here. */
+ return;
+ assert_se(r >= 0);
+
+ printf("%s encrypted: %s\n", p, yes_no(r));
+
+ assert_se(expect < 0 || ((r > 0) == (expect > 0)));
+}
+
+static void test_path_is_encrypted(void) {
+ log_info("/* %s */", __func__);
+
+ test_path_is_encrypted_one("/home", -1);
+ test_path_is_encrypted_one("/var", -1);
+ test_path_is_encrypted_one("/", -1);
+ test_path_is_encrypted_one("/proc", false);
+ test_path_is_encrypted_one("/sys", false);
+ test_path_is_encrypted_one("/dev", false);
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO);
test_rename_noreplace();
test_chmod_and_chown();
test_chmod_and_chown_unsafe();
+ test_path_is_encrypted();
return 0;
}
int r;
const char *name;
- _cleanup_free_ char *value, *filtered;
+ _cleanup_free_ char *value = NULL, *filtered = NULL;
r = fstab_filter_options(opts, remove, &name, &value, &filtered);
log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "hashmap.h"
+#include "string-util.h"
#include "util.h"
unsigned custom_counter = 0;
assert_se(iterated_cache_free(c) == NULL);
}
+static void test_hashmap_put_strdup(void) {
+ _cleanup_hashmap_free_ Hashmap *m = NULL;
+ char *s;
+
+ /* We don't have ordered_hashmap_put_strdup() yet. If it is added,
+ * these tests should be moved to test-hashmap-plain.c. */
+
+ log_info("/* %s */", __func__);
+
+ assert_se(hashmap_put_strdup(&m, "foo", "bar") == 1);
+ assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+ assert_se(hashmap_put_strdup(&m, "foo", "BAR") == -EEXIST);
+ assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+ assert_se(hashmap_contains(m, "foo"));
+
+ s = hashmap_get(m, "foo");
+ assert_se(streq(s, "bar"));
+
+ assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 1);
+ assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 0);
+ assert_se(hashmap_put_strdup(&m, "xxx", "BAR") == -EEXIST);
+ assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 0);
+ assert_se(hashmap_contains(m, "xxx"));
+
+ s = hashmap_get(m, "xxx");
+ assert_se(streq(s, "bar"));
+}
+
+static void test_hashmap_put_strdup_null(void) {
+ _cleanup_hashmap_free_ Hashmap *m = NULL;
+ char *s;
+
+ log_info("/* %s */", __func__);
+
+ assert_se(hashmap_put_strdup(&m, "foo", "bar") == 1);
+ assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+ assert_se(hashmap_put_strdup(&m, "foo", NULL) == -EEXIST);
+ assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+ assert_se(hashmap_contains(m, "foo"));
+
+ s = hashmap_get(m, "foo");
+ assert_se(streq(s, "bar"));
+
+ assert_se(hashmap_put_strdup(&m, "xxx", NULL) == 1);
+ assert_se(hashmap_put_strdup(&m, "xxx", "bar") == -EEXIST);
+ assert_se(hashmap_put_strdup(&m, "xxx", NULL) == 0);
+ assert_se(hashmap_contains(m, "xxx"));
+
+ s = hashmap_get(m, "xxx");
+ assert_se(s == NULL);
+}
+
int main(int argc, const char *argv[]) {
/* This file tests in test-hashmap-plain.c, and tests in test-hashmap-ordered.c, which is generated
* from test-hashmap-plain.c. Hashmap tests should be added to test-hashmap-plain.c, and here only if
test_trivial_compare_func();
test_string_compare_func();
test_iterated_cache();
+ test_hashmap_put_strdup();
+ test_hashmap_put_strdup_null();
return 0;
}
unlink(path);
}
+static void test_hostname_malloc(void) {
+ _cleanup_free_ char *h = NULL, *l = NULL;
+
+ assert_se(h = gethostname_malloc());
+ log_info("hostname_malloc: \"%s\"", h);
+
+ assert_se(l = gethostname_short_malloc());
+ log_info("hostname_short_malloc: \"%s\"", l);
+}
+
+static void test_fallback_hostname(void) {
+ if (!hostname_is_valid(FALLBACK_HOSTNAME, false)) {
+ log_error("Configured fallback hostname \"%s\" is not valid.", FALLBACK_HOSTNAME);
+ exit(EXIT_FAILURE);
+ }
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
test_hostname_is_valid();
test_hostname_cleanup();
test_read_etc_hostname();
+ test_hostname_malloc();
+
+ test_fallback_hostname();
return 0;
}
assert_se(symlink("a.service", p) >= 0);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
p = strjoina(root, "/usr/lib/systemd/system/c.service");
assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
p = strjoina(root, "/usr/lib/systemd/system/d.service");
assert_se(symlink("c.service", p) >= 0);
/* This one is interesting, as d follows a relative, then an absolute symlink */
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 1);
changes = NULL; n_changes = 0;
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
/* Enabling it again should succeed but be a NOP */
assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
changes = NULL; n_changes = 0;
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
/* Disabling a disabled unit must succeed but be a NOP */
assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
changes = NULL; n_changes = 0;
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
/* Let's try to reenable */
changes = NULL; n_changes = 0;
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
}
static void test_linked_units(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 1);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_ALIAS);
assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 1);
got_no = true;
assert_se(fl->state == UNIT_FILE_DISABLED);
} else
- assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT));
+ assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT, UNIT_FILE_ALIAS));
}
unit_file_list_free(h);
assert_se(!locale_is_valid("\x01gar\x02 bage\x03"));
}
+static void test_locale_is_installed(void) {
+ log_info("/* %s */", __func__);
+
+ /* Always available */
+ assert_se(locale_is_installed("POSIX") > 0);
+ assert_se(locale_is_installed("C") > 0);
+
+ /* Might, or might not be installed. */
+ assert_se(locale_is_installed("en_EN.utf8") >= 0);
+ assert_se(locale_is_installed("fr_FR.utf8") >= 0);
+ assert_se(locale_is_installed("fr_FR@euro") >= 0);
+ assert_se(locale_is_installed("fi_FI") >= 0);
+
+ /* Definitely not valid */
+ assert_se(locale_is_installed("") == 0);
+ assert_se(locale_is_installed("/usr/bin/foo") == 0);
+ assert_se(locale_is_installed("\x01gar\x02 bage\x03") == 0);
+
+ /* Definitely not installed */
+ assert_se(locale_is_installed("zz_ZZ") == 0);
+}
+
static void test_keymaps(void) {
_cleanup_strv_free_ char **kmaps = NULL;
char **p;
int main(int argc, char *argv[]) {
test_get_locales();
test_locale_is_valid();
+ test_locale_is_installed();
test_keymaps();
dump_special_glyphs();
static void test_struct(void) {
_cleanup_(prioq_freep) Prioq *q = NULL;
- _cleanup_(set_freep) Set *s = NULL;
+ _cleanup_set_free_ Set *s = NULL;
unsigned previous = 0, i;
struct test *t;
#include "alloc-util.h"
#include "env-util.h"
+#include "errno-util.h"
#include "log.h"
#include "macro.h"
#include "proc-cmdline.h"
int main(void) {
test_setup_logging(LOG_INFO);
+ if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
+ return log_tests_skipped("can't read /proc/cmdline");
+
test_proc_cmdline_parse();
test_proc_cmdline_override();
test_proc_cmdline_given(false);
#include <errno.h>
+#include "errno-util.h"
#include "format-util.h"
#include "log.h"
#include "procfs-util.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_BYTES_MAX)];
assert_se(procfs_tasks_get_current(&v) >= 0);
log_info("Current number of tasks: %" PRIu64, v);
- assert_se(procfs_tasks_get_limit(&v) >= 0);
+ r = procfs_tasks_get_limit(&v);
+ if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
+ return log_tests_skipped("can't read /proc/sys/kernel/pid_max");
+
+ assert_se(r >= 0);
log_info("Limit of tasks: %" PRIu64, v);
assert_se(v > 0);
assert_se(procfs_tasks_set_limit(v) >= 0);
test_genuine_random_bytes(0);
test_genuine_random_bytes(RANDOM_BLOCK);
test_genuine_random_bytes(RANDOM_ALLOW_RDRAND);
+ test_genuine_random_bytes(RANDOM_ALLOW_INSECURE);
test_pseudo_random_bytes();
#include "sd-hwdb.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "errno.h"
#include "tests.h"
log_info("/* %s */", __func__);
r = sd_hwdb_new(&hwdb);
- if (r == -ENOENT)
+ if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
return r;
assert_se(r == 0);
#include "alloc-util.h"
#include "fd-util.h"
+#include "fileio.h"
#include "macro.h"
#include "memory-util.h"
#include "missing_sched.h"
static void test_protect_sysctl(void) {
pid_t pid;
+ _cleanup_free_ char *seccomp = NULL;
log_info("/* %s */", __func__);
return;
}
+ assert_se(get_proc_field("/proc/self/status", "Seccomp", WHITESPACE, &seccomp) == 0);
+ if (!streq(seccomp, "0"))
+ log_warning("Warning: seccomp filter detected, results may be unreliable for %s", __func__);
+
pid = fork();
assert_se(pid >= 0);
#include "set.h"
#include "strv.h"
+const bool mempool_use_allowed = VALGRIND;
+
static void test_set_steal_first(void) {
_cleanup_set_free_ Set *m = NULL;
int seen[3] = {};
assert_se(strv_length(t) == 3);
}
+static void test_set_put_strdup(void) {
+ _cleanup_set_free_ Set *m = NULL;
+
+ assert_se(set_put_strdup(&m, "aaa") == 1);
+ assert_se(set_put_strdup(&m, "aaa") == 0);
+ assert_se(set_put_strdup(&m, "bbb") == 1);
+ assert_se(set_put_strdup(&m, "bbb") == 0);
+ assert_se(set_put_strdup(&m, "aaa") == 0);
+ assert_se(set_size(m) == 2);
+}
+
+static void test_set_put_strdupv(void) {
+ _cleanup_set_free_ Set *m = NULL;
+
+ assert_se(set_put_strdupv(&m, STRV_MAKE("aaa", "aaa", "bbb", "bbb", "aaa")) == 2);
+ assert_se(set_put_strdupv(&m, STRV_MAKE("aaa", "aaa", "bbb", "bbb", "ccc")) == 1);
+ assert_se(set_size(m) == 3);
+}
+
int main(int argc, const char *argv[]) {
test_set_steal_first();
test_set_free_with_destructor();
test_set_free_with_hash_ops();
test_set_put();
+ test_set_put_strdup();
+ test_set_put_strdupv();
return 0;
}
_cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL;
log_info("/* %s */", __func__);
- assert(parse_sleep_config(&sleep_config) == 0);
+ assert_se(parse_sleep_config(&sleep_config) == 0);
_cleanup_free_ char *sum, *sus, *him, *his, *hym, *hys;
assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV);
}
+static void test_in_addr_ifindex_name_from_string_auto_one(const char *a, const char *expected) {
+ int family, ifindex;
+ union in_addr_union ua;
+ _cleanup_free_ char *server_name = NULL;
+
+ assert_se(in_addr_ifindex_name_from_string_auto(a, &family, &ua, &ifindex, &server_name) >= 0);
+ assert_se(streq_ptr(server_name, expected));
+}
+
+static void test_in_addr_ifindex_name_from_string_auto(void) {
+ log_info("/* %s */", __func__);
+
+ test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1", NULL);
+ test_in_addr_ifindex_name_from_string_auto_one("192.168.0.1#test.com", "test.com");
+ test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19", NULL);
+ test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
+}
+
static void test_sockaddr_equal(void) {
union sockaddr_union a = {
.in.sin_family = AF_INET,
test_in_addr_to_string();
test_in_addr_ifindex_to_string();
test_in_addr_ifindex_from_string_auto();
+ test_in_addr_ifindex_name_from_string_auto();
test_sockaddr_equal();
#include "alloc-util.h"
#include "log.h"
#include "specifier.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
}
static void test_specifier_escape(void) {
+ log_info("/* %s */", __func__);
+
test_specifier_escape_one(NULL, NULL);
test_specifier_escape_one("", "");
test_specifier_escape_one("%", "%%");
}
static void test_specifier_escape_strv(void) {
+ log_info("/* %s */", __func__);
+
test_specifier_escape_strv_one(NULL, NULL);
test_specifier_escape_strv_one(STRV_MAKE(NULL), STRV_MAKE(NULL));
test_specifier_escape_strv_one(STRV_MAKE(""), STRV_MAKE(""));
test_specifier_escape_strv_one(STRV_MAKE("foo"), STRV_MAKE("foo"));
test_specifier_escape_strv_one(STRV_MAKE("%"), STRV_MAKE("%%"));
- test_specifier_escape_strv_one(STRV_MAKE("foo", "%", "foo%", "%foo", "foo%foo", "quux", "%%%"), STRV_MAKE("foo", "%%", "foo%%", "%%foo", "foo%%foo", "quux", "%%%%%%"));
+ test_specifier_escape_strv_one(STRV_MAKE("foo", "%", "foo%", "%foo", "foo%foo", "quux", "%%%"),
+ STRV_MAKE("foo", "%%", "foo%%", "%%foo", "foo%%foo", "quux", "%%%%%%"));
+}
+
+/* Any specifier functions which don't need an argument. */
+static const Specifier specifier_table[] = {
+ { 'm', specifier_machine_id, NULL },
+ { 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
+ { 'l', specifier_short_host_name, NULL },
+ { 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
+
+ { 'g', specifier_group_name, NULL },
+ { 'G', specifier_group_id, NULL },
+ { 'U', specifier_user_id, NULL },
+ { 'u', specifier_user_name, NULL },
+ { 'h', specifier_user_home, NULL },
+
+ { 'T', specifier_tmp_dir, NULL },
+ { 'V', specifier_var_tmp_dir, NULL },
+ {}
+};
+
+static void test_specifiers(void) {
+ log_info("/* %s */", __func__);
+
+ for (const Specifier *s = specifier_table; s->specifier; s++) {
+ char spec[3];
+ _cleanup_free_ char *resolved = NULL;
+
+ xsprintf(spec, "%%%c", s->specifier);
+
+ assert_se(specifier_printf(spec, specifier_table, NULL, &resolved) >= 0);
+
+ log_info("%%%c → %s", s->specifier, resolved);
+ }
}
int main(int argc, char *argv[]) {
test_specifier_escape();
test_specifier_escape_strv();
+ test_specifiers();
return 0;
}
static void test_specifier_printf(void) {
static const Specifier table[] = {
- { 'a', specifier_string, (char*) "AAAA" },
- { 'b', specifier_string, (char*) "BBBB" },
- { 'm', specifier_machine_id, NULL },
- { 'B', specifier_boot_id, NULL },
- { 'H', specifier_host_name, NULL },
+ { 'X', specifier_string, (char*) "AAAA" },
+ { 'Y', specifier_string, (char*) "BBBB" },
+ { 'm', specifier_machine_id, NULL },
+ { 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
{ 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
{}
};
log_info("/* %s */", __func__);
- r = specifier_printf("xxx a=%a b=%b yyy", table, NULL, &w);
+ r = specifier_printf("xxx a=%X b=%Y yyy", table, NULL, &w);
assert_se(r >= 0);
assert_se(w);
assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
free(w);
- r = specifier_printf("machine=%m, boot=%B, host=%H, version=%v", table, NULL, &w);
+ r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", table, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
+
+ w = mfree(w);
+ specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", table, NULL, &w);
+ if (w)
+ puts(w);
}
static void test_str_in_set(void) {
else
d = b - a;
- assert(d < 10*USEC_PER_SEC);
+ assert_se(d < 10*USEC_PER_SEC);
}
static void test_usec_shift_clock(void) {
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
+#include "errno-util.h"
#include "log.h"
#include "path-util.h"
#include "string-util.h"
_cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
_cleanup_free_ char *testdata_fname = NULL;
MountPoint *m;
+ int r;
log_info("/* %s(\"%s\") */", __func__, fname ?: "/proc/swaps");
}
LIST_HEAD_INIT(mp_list_head);
- assert_se(swap_list_get(fname, &mp_list_head) >= 0);
+ r = swap_list_get(fname, &mp_list_head);
+ if (ERRNO_IS_PRIVILEGE(r))
+ return;
+ assert_se(r >= 0);
LIST_FOREACH(mount_point, m, mp_list_head)
log_debug("path=%s o=%s f=0x%lx try-ro=%s dev=%u:%u",
if (r < 0)
return log_error_errno(r, "Failed to parse time specification '%s': %m", argv[1]);
- r = sd_bus_call_method(bus,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "SetTime",
- &error,
- NULL,
- "xbb", (int64_t) t, relative, interactive);
+ r = bus_call_method(
+ bus,
+ bus_timedate,
+ "SetTime",
+ &error,
+ NULL,
+ "xbb", (int64_t) t, relative, interactive);
if (r < 0)
return log_error_errno(r, "Failed to set time: %s", bus_error_message(&error, r));
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(bus,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "SetTimezone",
- &error,
- NULL,
- "sb", argv[1], arg_ask_password);
+ r = bus_call_method(bus, bus_timedate, "SetTimezone", &error, NULL, "sb", argv[1], arg_ask_password);
if (r < 0)
return log_error_errno(r, "Failed to set time zone: %s", bus_error_message(&error, r));
if (b < 0)
return log_error_errno(b, "Failed to parse local RTC setting '%s': %m", argv[1]);
- r = sd_bus_call_method(bus,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "SetLocalRTC",
- &error,
- NULL,
- "bbb", b, arg_adjust_system_clock, arg_ask_password);
+ r = bus_call_method(
+ bus,
+ bus_timedate,
+ "SetLocalRTC",
+ &error,
+ NULL,
+ "bbb", b, arg_adjust_system_clock, arg_ask_password);
if (r < 0)
return log_error_errno(r, "Failed to set local RTC: %s", bus_error_message(&error, r));
if (b < 0)
return log_error_errno(b, "Failed to parse NTP setting '%s': %m", argv[1]);
- r = sd_bus_call_method(bus,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "SetNTP",
- &error,
- NULL,
- "bb", b, arg_ask_password);
+ r = bus_call_method(bus, bus_timedate, "SetNTP", &error, NULL, "bb", b, arg_ask_password);
if (r < 0)
return log_error_errno(r, "Failed to set ntp: %s", bus_error_message(&error, r));
int r;
char** zones;
- r = sd_bus_call_method(bus,
- "org.freedesktop.timedate1",
- "/org/freedesktop/timedate1",
- "org.freedesktop.timedate1",
- "ListTimezones",
- &error,
- &reply,
- NULL);
+ r = bus_call_method(bus, bus_timedate, "ListTimezones", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request list of time zones: %s",
bus_error_message(&error, r));
return r;
assert(r < 0);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "GetLinkByName",
- &error,
- &reply,
- "s", str);
+ r = bus_call_method(bus, bus_network_mgr, "GetLinkByName", &error, &reply, "s", str);
if (r < 0)
return log_error_errno(r, "Failed to get ifindex of interfaces %s: %s", str, bus_error_message(&error, r));
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_message_new_method_call(
- bus,
- &req,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "SetLinkNTP");
+ r = bus_message_new_method_call(bus, &req, bus_network_mgr, "SetLinkNTP");
if (r < 0)
return bus_log_create_error(r);
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.network1",
- "/org/freedesktop/network1",
- "org.freedesktop.network1.Manager",
- "RevertLinkNTP",
- &error,
- NULL,
- "i", ifindex);
+ r = bus_call_method(bus, bus_network_mgr, "RevertLinkNTP", &error, NULL, "i", ifindex);
if (r < 0)
return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
#include "bus-error.h"
#include "bus-log-control-api.h"
#include "bus-polkit.h"
+#include "bus-util.h"
#include "clock-util.h"
#include "conf-files.h"
#include "def.h"
#include "missing_capability.h"
#include "path-util.h"
#include "selinux-util.h"
+#include "service-util.h"
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
assert(bus);
assert(error);
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
start ? "StartUnit" : "StopUnit",
error,
&reply,
log_unit_info(u, "%s unit.", enable ? "Enabling" : "Disabling");
if (enable)
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"EnableUnitFiles",
error,
NULL,
u->name,
false, true);
else
- r = sd_bus_call_method(
+ r = bus_call_method(
bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"DisableUnitFiles",
error,
NULL,
if (r < 0)
return r;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "Reload",
- error,
- NULL,
- NULL);
+ r = bus_call_method(bus, bus_systemd_mgr, "Reload", error, NULL, NULL);
if (r < 0)
return r;
u->path = mfree(u->path);
if (!c->slot_job_removed) {
- r = sd_bus_match_signal_async(
+ r = bus_match_signal_async(
bus,
&slot,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
+ bus_systemd_mgr,
"JobRemoved",
match_job_removed, NULL, c);
if (r < 0)
SD_BUS_VTABLE_END,
};
+const BusObjectImplementation manager_object = {
+ "/org/freedesktop/timedate1",
+ "org.freedesktop.timedate1",
+ .vtables = BUS_VTABLES(timedate_vtable),
+};
+
static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
if (r < 0)
return log_error_errno(r, "Failed to get system bus connection: %m");
- r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
+ r = bus_add_implementation(bus, &manager_object, c);
if (r < 0)
- return log_error_errno(r, "Failed to register object: %m");
+ return r;
r = bus_log_control_api_register(bus);
if (r < 0)
log_setup_service();
- umask(0022);
+ r = service_parse_argv("systemd-timedated.service",
+ "Manage the system clock and timezone and NTP enablement.",
+ BUS_IMPLEMENTATIONS(&manager_object,
+ &log_control_object),
+ argc, argv);
+ if (r <= 0)
+ return r;
- if (argc != 1)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
+ umask(0022);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
.iov_base = &ntpmsg,
.iov_len = sizeof(ntpmsg),
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct timeval))];
- } control;
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct timeval))) control;
union sockaddr_union server_addr;
struct msghdr msghdr = {
.msg_iov = &iov,
return manager_connect(m);
}
- len = recvmsg(fd, &msghdr, MSG_DONTWAIT);
+ len = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
+ if (len == -EAGAIN)
+ return 0;
if (len < 0) {
- if (errno == EAGAIN)
- return 0;
-
- log_warning("Error receiving message. Disconnecting.");
+ log_warning_errno(len, "Error receiving message, disconnecting: %m");
return manager_connect(m);
}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fd-util.h"
+#include "offline-passwd.h"
+#include "path-util.h"
+#include "user-util.h"
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free);
+
+int name_to_uid_offline(
+ const char *root,
+ const char *user,
+ uid_t *ret_uid,
+ Hashmap **cache) {
+
+ void *found;
+ int r;
+
+ assert(user);
+ assert(ret_uid);
+ assert(cache);
+
+ if (!*cache) {
+ _cleanup_(hashmap_freep) Hashmap *uid_by_name = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ struct passwd *pw;
+ const char *passwd_path;
+
+ passwd_path = prefix_roota(root, "/etc/passwd");
+ f = fopen(passwd_path, "re");
+ if (!f)
+ return errno == ENOENT ? -ESRCH : -errno;
+
+ uid_by_name = hashmap_new(&uid_gid_hash_ops);
+ if (!uid_by_name)
+ return -ENOMEM;
+
+ while ((r = fgetpwent_sane(f, &pw)) > 0) {
+ _cleanup_free_ char *n = NULL;
+
+ n = strdup(pw->pw_name);
+ if (!n)
+ return -ENOMEM;
+
+ r = hashmap_put(uid_by_name, n, UID_TO_PTR(pw->pw_uid));
+ if (r == -EEXIST) {
+ log_warning_errno(r, "Duplicate entry in %s for %s: %m", passwd_path, pw->pw_name);
+ continue;
+ }
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(n);
+ }
+
+ *cache = TAKE_PTR(uid_by_name);
+ }
+
+ found = hashmap_get(*cache, user);
+ if (!found)
+ return -ESRCH;
+
+ *ret_uid = PTR_TO_UID(found);
+ return 0;
+}
+
+int name_to_gid_offline(
+ const char *root,
+ const char *group,
+ gid_t *ret_gid,
+ Hashmap **cache) {
+
+ void *found;
+ int r;
+
+ assert(group);
+ assert(ret_gid);
+ assert(cache);
+
+ if (!*cache) {
+ _cleanup_(hashmap_freep) Hashmap *gid_by_name = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ struct group *gr;
+ const char *group_path;
+
+ group_path = prefix_roota(root, "/etc/group");
+ f = fopen(group_path, "re");
+ if (!f)
+ return errno == ENOENT ? -ESRCH : -errno;
+
+ gid_by_name = hashmap_new(&uid_gid_hash_ops);
+ if (!gid_by_name)
+ return -ENOMEM;
+
+ while ((r = fgetgrent_sane(f, &gr)) > 0) {
+ _cleanup_free_ char *n = NULL;
+
+ n = strdup(gr->gr_name);
+ if (!n)
+ return -ENOMEM;
+
+ r = hashmap_put(gid_by_name, n, GID_TO_PTR(gr->gr_gid));
+ if (r == -EEXIST) {
+ log_warning_errno(r, "Duplicate entry in %s for %s: %m", group_path, gr->gr_name);
+ continue;
+ }
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(n);
+ }
+
+ *cache = TAKE_PTR(gid_by_name);
+ }
+
+ found = hashmap_get(*cache, group);
+ if (!found)
+ return -ESRCH;
+
+ *ret_gid = PTR_TO_GID(found);
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include "hashmap.h"
+
+int name_to_uid_offline(const char *root, const char *user, uid_t *ret_uid, Hashmap **cache);
+int name_to_gid_offline(const char *root, const char *group, gid_t *ret_gid, Hashmap **cache);
#include "main-func.h"
#include "mkdir.h"
#include "mountpoint-util.h"
+#include "offline-passwd.h"
#include "pager.h"
#include "parse-util.h"
#include "path-lookup.h"
{ 'm', specifier_machine_id_safe, NULL },
{ 'b', specifier_boot_id, NULL },
{ 'H', specifier_host_name, NULL },
+ { 'l', specifier_short_host_name, NULL },
{ 'v', specifier_kernel_release, NULL },
+ { 'a', specifier_architecture, NULL },
+ { 'o', specifier_os_id, NULL },
+ { 'w', specifier_os_version_id, NULL },
+ { 'B', specifier_os_build_id, NULL },
+ { 'W', specifier_os_variant_id, NULL },
{ 'g', specifier_group_name, NULL },
{ 'G', specifier_group_id, NULL },
* not considered as an error so log at LOG_NOTICE only for the first time
* and then downgrade this to LOG_DEBUG for the rest. */
- log_full(notified ? LOG_DEBUG : LOG_NOTICE,
- "[%s:%u] Failed to resolve specifier: %s, skipping",
- filename, line,
- arg_user ? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
+ log_syntax(NULL,
+ notified ? LOG_DEBUG : LOG_NOTICE,
+ filename, line, 0,
+ "Failed to resolve specifier: %s, skipping",
+ arg_user ? "Required $XDG_... variable not defined" : "uninitialized /etc detected");
if (!notified)
log_notice("All rules containing unresolvable specifiers will be skipped.");
if (r > 0)
return -r; /* already warned */
+
+ /* The above procfs paths don't work if /proc is not mounted. */
+ if (r == -ENOENT && proc_mounted() == 0)
+ r = -ENOSYS;
+
if (r == -EOPNOTSUPP) {
log_debug_errno(r, "ACLs not supported by file system at %s", path);
return 0;
case SET_XATTR:
case RECURSIVE_SET_XATTR:
- assert(i->xattrs);
-
- STRV_FOREACH (xattr, i->xattrs) {
+ STRV_FOREACH(xattr, i->xattrs) {
r = specifier_printf(*xattr, specifier_table, NULL, &resolved);
if (r < 0)
return r;
return 0;
}
-static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
+static int find_uid(const char *user, uid_t *ret_uid, Hashmap **cache) {
+ int r;
+
+ assert(user);
+ assert(ret_uid);
+
+ /* First: parse as numeric UID string */
+ r = parse_uid(user, ret_uid);
+ if (r >= 0)
+ return r;
+
+ /* Second: pass to NSS if we are running "online" */
+ if (!arg_root)
+ return get_user_creds(&user, ret_uid, NULL, NULL, NULL, 0);
+
+ /* Third, synthesize "root" unconditionally */
+ if (streq(user, "root")) {
+ *ret_uid = 0;
+ return 0;
+ }
+
+ /* Fourth: use fgetpwent() to read /etc/passwd directly, if we are "offline" */
+ return name_to_uid_offline(arg_root, user, ret_uid, cache);
+}
+
+static int find_gid(const char *group, gid_t *ret_gid, Hashmap **cache) {
+ int r;
+
+ assert(group);
+ assert(ret_gid);
+
+ /* First: parse as numeric GID string */
+ r = parse_gid(group, ret_gid);
+ if (r >= 0)
+ return r;
+
+ /* Second: pass to NSS if we are running "online" */
+ if (!arg_root)
+ return get_group_creds(&group, ret_gid, 0);
+
+ /* Third, synthesize "root" unconditionally */
+ if (streq(group, "root")) {
+ *ret_gid = 0;
+ return 0;
+ }
+
+ /* Fourth: use fgetgrent() to read /etc/group directly, if we are "offline" */
+ return name_to_gid_offline(arg_root, group, ret_gid, cache);
+}
+
+static int parse_line(
+ const char *fname,
+ unsigned line,
+ const char *buffer,
+ bool *invalid_config,
+ Hashmap **uid_cache,
+ Hashmap **gid_cache) {
_cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
_cleanup_(item_free_contents) Item i = {};
if (IN_SET(r, -EINVAL, -EBADSLT))
/* invalid quoting and such or an unknown specifier */
*invalid_config = true;
- return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to parse line: %m");
} else if (r < 2) {
*invalid_config = true;
- log_error("[%s:%u] Syntax error.", fname, line);
- return -EIO;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Syntax error.");
}
if (!empty_or_dash(buffer)) {
if (isempty(action)) {
*invalid_config = true;
- log_error("[%s:%u] Command too short '%s'.", fname, line, action);
- return -EINVAL;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Command too short '%s'.", action);
}
for (pos = 1; action[pos]; pos++) {
allow_failure = true;
else {
*invalid_config = true;
- log_error("[%s:%u] Unknown modifiers in command '%s'",
- fname, line, action);
- return -EINVAL;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Unknown modifiers in command '%s'", action);
}
}
if (boot && !arg_boot) {
- log_debug("Ignoring entry %s \"%s\" because --boot is not specified.",
- action, path);
+ log_syntax(NULL, LOG_DEBUG, fname, line, 0, "Ignoring entry %s \"%s\" because --boot is not specified.", action, path);
return 0;
}
if (r < 0) {
if (IN_SET(r, -EINVAL, -EBADSLT))
*invalid_config = true;
- return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, path);
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to replace specifiers in '%s': %m", path);
}
r = patch_var_run(fname, line, &i.path);
case RELABEL_PATH:
case RECURSIVE_RELABEL_PATH:
if (i.argument)
- log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
+ log_syntax(NULL, LOG_WARNING, fname, line, 0, "%c lines don't take argument fields, ignoring.", i.type);
break;
case WRITE_FILE:
if (!i.argument) {
*invalid_config = true;
- log_error("[%s:%u] Write file requires argument.", fname, line);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Write file requires argument.");
}
break;
case COPY_FILES:
if (!i.argument) {
- i.argument = path_join(arg_root, "/usr/share/factory", i.path);
+ i.argument = path_join("/usr/share/factory", i.path);
if (!i.argument)
return log_oom();
} else if (!path_is_absolute(i.argument)) {
*invalid_config = true;
- log_error("[%s:%u] Source path is not absolute.", fname, line);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Source path '%s' is not absolute.", i.argument);
+
+ }
- } else if (arg_root) {
+ if (!empty_or_root(arg_root)) {
char *p;
p = path_join(arg_root, i.argument);
case CREATE_BLOCK_DEVICE:
if (!i.argument) {
*invalid_config = true;
- log_error("[%s:%u] Device file requires argument.", fname, line);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Device file requires argument.");
}
r = parse_dev(i.argument, &i.major_minor);
if (r < 0) {
*invalid_config = true;
- log_error_errno(r, "[%s:%u] Can't parse device file major/minor '%s'.", fname, line, i.argument);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Can't parse device file major/minor '%s'.", i.argument);
}
break;
case RECURSIVE_SET_XATTR:
if (!i.argument) {
*invalid_config = true;
- log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+ "Set extended attribute requires argument.");
}
r = parse_xattrs_from_arg(&i);
if (r < 0)
case RECURSIVE_SET_ACL:
if (!i.argument) {
*invalid_config = true;
- log_error("[%s:%u] Set ACLs requires argument.", fname, line);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+ "Set ACLs requires argument.");
}
r = parse_acls_from_arg(&i);
if (r < 0)
case RECURSIVE_SET_ATTRIBUTE:
if (!i.argument) {
*invalid_config = true;
- log_error("[%s:%u] Set file attribute requires argument.", fname, line);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+ "Set file attribute requires argument.");
}
r = parse_attribute_from_arg(&i);
if (IN_SET(r, -EINVAL, -EBADSLT))
break;
default:
- log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type);
*invalid_config = true;
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+ "Unknown command type '%c'.", (char) i.type);
}
if (!path_is_absolute(i.path)) {
- log_error("[%s:%u] Path '%s' not absolute.", fname, line, i.path);
*invalid_config = true;
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
+ "Path '%s' not absolute.", i.path);
}
path_simplify(i.path, false);
if (r < 0) {
if (IN_SET(r, -EINVAL, -EBADSLT))
*invalid_config = true;
- return log_error_errno(r, "[%s:%u] Failed to substitute specifiers in argument: %m",
- fname, line);
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to substitute specifiers in argument: %m");
}
- if (arg_root) {
+ if (!empty_or_root(arg_root)) {
char *p;
p = path_join(arg_root, i.path);
}
if (!empty_or_dash(user)) {
- const char *u = user;
-
- r = get_user_creds(&u, &i.uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
+ r = find_uid(user, &i.uid, uid_cache);
if (r < 0) {
*invalid_config = true;
- return log_error_errno(r, "[%s:%u] Unknown user '%s'.", fname, line, user);
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", user);
}
i.uid_set = true;
}
if (!empty_or_dash(group)) {
- const char *g = group;
-
- r = get_group_creds(&g, &i.gid, USER_CREDS_ALLOW_MISSING);
+ r = find_gid(group, &i.gid, gid_cache);
if (r < 0) {
*invalid_config = true;
- log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
- return r;
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s'.", group);
}
i.gid_set = true;
mm++;
}
- if (parse_mode(mm, &m) < 0) {
+ r = parse_mode(mm, &m);
+ if (r < 0) {
*invalid_config = true;
- log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid mode '%s'.", mode);
}
i.mode = m;
a++;
}
- if (parse_sec(a, &i.age) < 0) {
+ r = parse_sec(a, &i.age);
+ if (r < 0) {
*invalid_config = true;
- log_error("[%s:%u] Invalid age '%s'.", fname, line, age);
- return -EBADMSG;
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Invalid age '%s'.", age);
}
i.age_set = true;
for (n = 0; n < existing->n_items; n++) {
if (!item_compatible(existing->items + n, &i) && !i.append_or_force) {
- log_notice("[%s:%u] Duplicate line for path \"%s\", ignoring.",
- fname, line, i.path);
+ log_syntax(NULL, LOG_NOTICE, fname, line, 0, "Duplicate line for path \"%s\", ignoring.", i.path);
return 0;
}
}
break;
case ARG_ROOT:
- r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;
}
static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
+ _cleanup_(hashmap_freep) Hashmap *uid_cache = NULL, *gid_cache = NULL;
_cleanup_fclose_ FILE *_f = NULL;
Iterator iterator;
unsigned v = 0;
if (IN_SET(*l, 0, '#'))
continue;
- k = parse_line(fn, v, l, &invalid_line);
+ k = parse_line(fn, v, l, &invalid_line, &uid_cache, &gid_cache);
if (k < 0) {
if (invalid_line)
/* Allow reporting with a special code if the caller requested this */
Link.CombinedChannels, config_parse_channel, 0, offsetof(link_config, channels)
Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise)
Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
+Link.RxMiniBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
+Link.RxJumboBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring)
Link.RxFlowControl, config_parse_tristate, 0, offsetof(link_config, rx_flow_control)
Link.TxFlowControl, config_parse_tristate, 0, offsetof(link_config, tx_flow_control)
#include <linux/netdevice.h>
#include <netinet/ether.h>
+#include <unistd.h>
#include "sd-device.h"
#include "sd-netlink.h"
return 0;
}
- if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
+ if (!condition_test_list(link->conditions, environ, NULL, NULL, NULL)) {
log_debug("%s: Conditions do not match the system environment, skipping.", filename);
return 0;
}
}
int link_config_load(link_config_ctx *ctx) {
- _cleanup_strv_free_ char **files;
+ _cleanup_strv_free_ char **files = NULL;
char **f;
int r;
if (want_random) {
log_device_debug(device, "Using random bytes to generate MAC");
- random_bytes(mac->ether_addr_octet, ETH_ALEN);
+
+ /* We require genuine randomness here, since we want to make sure we won't collide with other
+ * systems booting up at the very same time. We do allow RDRAND however, since this is not
+ * cryptographic key material. */
+ genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND);
} else {
uint64_t result;
log_warning_errno(r, "Could not set channels of %s: %m", old_name);
}
- if (config->ring.rx_pending_set || config->ring.tx_pending_set) {
+ if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring);
if (r < 0)
log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
}
- r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
- if (r < 0)
- log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
+ if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
+ r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
+ if (r < 0)
+ log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
+ }
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0)
_cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
struct udev_ctrl_msg_wire msg_wire;
struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
- char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
struct msghdr smsg = {
.msg_iov = &iov,
.msg_iovlen = 1,
- .msg_control = cred_msg,
- .msg_controllen = sizeof(cred_msg),
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
};
struct cmsghdr *cmsg;
struct ucred *cred;
if (size == 0)
return 0; /* Client disconnects? */
- size = recvmsg(fd, &smsg, 0);
- if (size < 0) {
- if (errno != EINTR)
- return log_error_errno(errno, "Failed to receive ctrl message: %m");
-
+ size = recvmsg_safe(fd, &smsg, 0);
+ if (size == -EINTR)
return 0;
- }
+ if (size < 0)
+ return log_error_errno(size, "Failed to receive ctrl message: %m");
cmsg_close_all(&smsg);
if (isempty(line_str))
return 0;
- line = strdup(line_str);
+ /* We use memdup_suffix0() here, since we want to add a second NUL byte to the end, since possibly
+ * some parsers might turn this into a "nulstr", which requires an extra NUL at the end. */
+ line = memdup_suffix0(line_str, strlen(line_str) + 1);
if (!line)
return log_oom();
match = isempty(str);
break;
case MATCH_TYPE_SUBSYSTEM:
- NULSTR_FOREACH(i, "subsystem\0class\0bus\0")
- if (streq(i, str)) {
- match = true;
- break;
- }
+ match = STR_IN_SET(str, "subsystem", "class", "bus");
break;
case MATCH_TYPE_PLAIN_WITH_EMPTY:
if (isempty(str)) {
static bool arg_verbose = false;
static bool arg_dry_run = false;
-static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_set) {
+static int exec_list(sd_device_enumerator *e, const char *action, Set **settle_set) {
sd_device *d;
int r, ret = 0;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
- _cleanup_set_free_free_ Set *settle_set = NULL;
+ _cleanup_set_free_ Set *settle_set = NULL;
usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
bool settle = false, ping = false;
int c, r;
}
if (settle) {
- settle_set = set_new(&string_hash_ops);
+ settle_set = set_new(&string_hash_ops_free);
if (!settle_set)
return log_oom();
default:
assert_not_reached("Unknown device type");
}
- r = exec_list(e, action, settle_set);
+
+ r = exec_list(e, action, settle ? &settle_set : NULL);
if (r < 0)
return r;
.iov_base = &msg,
.iov_len = sizeof(msg),
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control = {};
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
- struct cmsghdr *cmsg;
ssize_t size;
- struct ucred *ucred = NULL;
+ struct ucred *ucred;
struct worker *worker;
- size = recvmsg(fd, &msghdr, MSG_DONTWAIT);
- if (size < 0) {
- if (errno == EINTR)
- continue;
- else if (errno == EAGAIN)
- /* nothing more to read */
- break;
+ size = recvmsg_safe(fd, &msghdr, MSG_DONTWAIT);
+ if (size == -EINTR)
+ continue;
+ if (size == -EAGAIN)
+ /* nothing more to read */
+ break;
+ if (size < 0)
+ return log_error_errno(size, "Failed to receive message: %m");
- return log_error_errno(errno, "Failed to receive message: %m");
- } else if (size != sizeof(struct worker_message)) {
+ cmsg_close_all(&msghdr);
+
+ if (size != sizeof(struct worker_message)) {
log_warning("Ignoring worker message with invalid size %zi bytes", size);
continue;
}
- CMSG_FOREACH(cmsg, &msghdr)
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
- ucred = (struct ucred*) CMSG_DATA(cmsg);
-
+ ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid <= 0) {
log_warning("Ignoring worker message without valid PID");
continue;
printf("%s [OPTIONS...] COMMAND ...\n\n"
"%sShow user and group information.%s\n"
"\nCommands:\n"
- " user [USER…] Inspect user\n"
- " group [GROUP…] Inspect group\n"
- " users-in-group [GROUP…] Show users that are members of specified group(s)\n"
- " groups-of-user [USER…] Show groups the specified user(s) is a member of\n"
- " services Show enabled database services\n"
+ " user [USER…] Inspect user\n"
+ " group [GROUP…] Inspect group\n"
+ " users-in-group [GROUP…] Show users that are members of specified group(s)\n"
+ " groups-of-user [USER…] Show groups the specified user(s) is a member of\n"
+ " services Show enabled database services\n"
"\nOptions:\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --no-pager Do not pipe output into a pager\n"
- " --no-legend Do not show the headers and footers\n"
- " --output=MODE Select output mode (classic, friendly, table, json)\n"
- " -j Equivalent to --output=json\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --no-pager Do not pipe output into a pager\n"
+ " --no-legend Do not show the headers and footers\n"
+ " --output=MODE Select output mode (classic, friendly, table, json)\n"
+ " -j Equivalent to --output=json\n"
" -s --service=SERVICE[:SERVICE…]\n"
- " Query the specified service\n"
- " --with-nss=BOOL Control whether to include glibc NSS data\n"
- " -N Disable inclusion of glibc NSS data and disable synthesizing\n"
- " (Same as --with-nss=no --synthesize=no)\n"
- " --synthesize=BOOL Synthesize root/nobody user\n"
+ " Query the specified service\n"
+ " --with-nss=BOOL Control whether to include glibc NSS data\n"
+ " -N Do not synthesize or include glibc NSS data\n"
+ " (Same as --synthesize=no --with-nss=no)\n"
+ " --synthesize=BOOL Synthesize root/nobody user\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, ansi_highlight(), ansi_normal()
if (r < 0)
return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m");
- r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
+ r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755" TMPFS_LIMITS_ROOTFS);
if (r < 0)
goto finish_rmdir;
if (r < 0)
return log_error_errno(r, "Couldn't create overlay sysroot directory: %m");
- r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
+ r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755" TMPFS_LIMITS_ROOTFS);
if (r < 0)
goto finish;
--- /dev/null
+../TEST-01-BASIC/Makefile
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+set -e
+TEST_DESCRIPTION="test unit freezing and thawing via DBus and systemctl"
+TEST_NO_NSPAWN=1
+. $TEST_BASE_DIR/test-functions
+
+do_test "$@" 38
--- /dev/null
+4:3:2147..2
\ No newline at end of file
CombinedChannels=
Advertise=
RxBufferSize=
+RxMiniBufferSize=
+RxJumboBufferSize=
TxBufferSize=
RxFlowControl=
TxFlowControl=
Priority=
GroupForwardMask=
VLANFiltering=
+VLANProtocol=
MulticastIGMPVersion=
[VRF]
TableId=
MTUBytes=
Multicast=
MACAddress=
+Group=
[BridgeFDB]
VLANId=
MACAddress=
SendDecline=
MUDURL=
RouteMTUBytes=
+FallbackLeaseLifetimeSec=
[DHCPv6]
UseNTP=
UseDNS=
PrefixDelegationHint=
WithoutRA=
MUDURL=
+SendOption=
+RequestOptions=
+UserClass=
+VendorClass=
[Route]
Destination=
Protocol=
ReadKMsg=
ReadOnly=
ReadOnlyPaths=
+ReadWriteOnly=
ReadWritePaths=
RemoveIPC=
ReserveVT=
# SPDX-License-Identifier: LGPL-2.1+
-sanitize_address = custom_target(
- 'sanitize-address-fuzzers',
- output : 'sanitize-address-fuzzers',
+sanitize_address_undefined = custom_target(
+ 'sanitize-address-undefined-fuzzers',
+ output : 'sanitize-address-undefined-fuzzers',
command : [meson_build_sh,
project_source_root,
'@OUTPUT@',
'fuzzers',
- '-Db_lundef=false -Db_sanitize=address',
+ '-Db_lundef=false -Db_sanitize=address,undefined',
' '.join(cc.cmd_array()),
cxx_cmd])
-sanitizers = [['address', sanitize_address]]
+sanitizers = [['address,undefined', sanitize_address_undefined]]
if git.found()
out = run_command(
PATH_TO_INIT=$ROOTLIBDIR/systemd
[ "$SYSTEMD_JOURNALD" ] || SYSTEMD_JOURNALD=$(which -a $BUILD_DIR/systemd-journald $ROOTLIBDIR/systemd-journald 2>/dev/null | grep '^/' -m1)
+[ "$SYSTEMD_JOURNAL_REMOTE" ] || SYSTEMD_JOURNAL_REMOTE=$(which -a $BUILD_DIR/systemd-journal-remote $ROOTLIBDIR/systemd-journal-remote 2>/dev/null | grep '^/' -m1)
[ "$SYSTEMD" ] || SYSTEMD=$(which -a $BUILD_DIR/systemd $ROOTLIBDIR/systemd 2>/dev/null | grep '^/' -m1)
[ "$SYSTEMD_NSPAWN" ] || SYSTEMD_NSPAWN=$(which -a $BUILD_DIR/systemd-nspawn systemd-nspawn 2>/dev/null | grep '^/' -m1)
[ "$JOURNALCTL" ] || JOURNALCTL=$(which -a $BUILD_DIR/journalctl journalctl 2>/dev/null | grep '^/' -m1)
tar
tee
test
+ timeout
touch
tr
true
fi
for j in $1/*; do
- /usr/lib/systemd/systemd-journal-remote \
+ $SYSTEMD_JOURNAL_REMOTE \
-o $dest \
- --getter="journalctl -o export -D $j"
+ --getter="$JOURNALCTL -o export -D $j"
if [ -n "${TEST_SHOW_JOURNAL}" ]; then
echo "---- $j ----"
- journalctl --no-pager -o short-monotonic --no-hostname --priority=${TEST_SHOW_JOURNAL} -D $j
+ $JOURNALCTL --no-pager -o short-monotonic --no-hostname --priority=${TEST_SHOW_JOURNAL} -D $j
fi
rm -r $j
# /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
# dracut_install plymouth plymouthd
# else
- rm -f $initdir/{usr/lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,etc}/systemd/system/*/plymouth*
+ rm -f $initdir/{usr/lib,lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,lib,etc}/systemd/system/*/plymouth*
# fi
}
grep -q "^_PID=$PID" /output
grep -vq "^_PID=$PID" /output
+# https://github.com/systemd/systemd/issues/15654
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "This will\nusually fail\nand be truncated\n">/expected
+systemd-cat -t "$ID" /bin/sh -c 'env echo -n "This will";echo;env echo -n "usually fail";echo;env echo -n "and be truncated";echo;'
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=_TRANSPORT | grep -Pc "^stdout$") -eq 3 ]]
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=_LINE_BREAK | grep -Pc "^pid-change$") -eq 3 ]]
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=_PID | sort -u | grep -c "^.*$") -eq 3 ]]
+[[ $(journalctl -b -o cat -t "$ID" --output-fields=MESSAGE | grep -Pc "^(This will|usually fail|and be truncated)$") -eq 3 ]]
+
# Add new tests before here, the journald restarts below
# may make tests flappy.
sleep 3
[[ ! -f "/i-lose-my-logs" ]]
+# https://github.com/systemd/systemd/issues/15528
+journalctl --follow --file=/var/log/journal/*/* | head -n1 || [[ $? -eq 1 ]]
+
touch /testok
--- /dev/null
+[Service]
+ExecStart=/bin/sleep 3600
--- /dev/null
+[Unit]
+Description=TEST-38-FREEZER
+
+[Service]
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
+Type=oneshot
--- /dev/null
+#!/usr/bin/env bash
+
+set -ex
+set -o pipefail
+
+systemd-analyze log-level debug
+systemd-analyze log-target console
+
+unit=testsuite-38-sleep.service
+
+start_test_service() {
+ systemctl daemon-reload
+ systemctl start "${unit}"
+}
+
+dbus_freeze() {
+ local suffix=
+ suffix="${1##*.}"
+
+ local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+ local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+ busctl call \
+ org.freedesktop.systemd1 \
+ "${object_path}" \
+ org.freedesktop.systemd1.Unit \
+ Freeze
+}
+
+dbus_thaw() {
+ local suffix=
+ suffix="${1##*.}"
+
+ local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+ local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+ busctl call \
+ org.freedesktop.systemd1 \
+ "${object_path}" \
+ org.freedesktop.systemd1.Unit \
+ Thaw
+}
+
+dbus_freeze_unit() {
+ busctl call \
+ org.freedesktop.systemd1 \
+ /org/freedesktop/systemd1 \
+ org.freedesktop.systemd1.Manager \
+ FreezeUnit \
+ s \
+ "$1"
+}
+
+dbus_thaw_unit() {
+ busctl call \
+ org.freedesktop.systemd1 \
+ /org/freedesktop/systemd1 \
+ org.freedesktop.systemd1.Manager \
+ ThawUnit \
+ s \
+ "$1"
+}
+
+dbus_can_freeze() {
+ local suffix=
+ suffix="${1##*.}"
+
+ local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+ local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+ busctl get-property \
+ org.freedesktop.systemd1 \
+ "${object_path}" \
+ org.freedesktop.systemd1.Unit \
+ CanFreeze
+}
+
+check_freezer_state() {
+ local suffix=
+ suffix="${1##*.}"
+
+ local name="$(echo ${1%.$suffix} | sed s/-/_2d/g)"
+ local object_path="/org/freedesktop/systemd1/unit/${name}_2e${suffix}"
+
+ state=$(busctl get-property \
+ org.freedesktop.systemd1 \
+ "${object_path}" \
+ org.freedesktop.systemd1.Unit \
+ FreezerState | cut -d " " -f2 | tr -d '"')
+
+ [ "$state" = "$2" ] || {
+ echo "error: unexpected freezer state, expected: $2, actual: $state" >&2
+ exit 1
+ }
+}
+
+check_cgroup_state() {
+ grep -q "frozen $2" /sys/fs/cgroup/system.slice/"$1"/cgroup.events
+}
+
+test_dbus_api() {
+ echo "Test that DBus API works:"
+ echo -n " - Freeze(): "
+ dbus_freeze "${unit}"
+ check_freezer_state "${unit}" "frozen"
+ check_cgroup_state "$unit" 1
+ echo "[ OK ]"
+
+ echo -n " - Thaw(): "
+ dbus_thaw "${unit}"
+ check_freezer_state "${unit}" "running"
+ check_cgroup_state "$unit" 0
+ echo "[ OK ]"
+
+ echo -n " - FreezeUnit(): "
+ dbus_freeze_unit "${unit}"
+ check_freezer_state "${unit}" "frozen"
+ check_cgroup_state "$unit" 1
+ echo "[ OK ]"
+
+ echo -n " - ThawUnit(): "
+ dbus_thaw_unit "${unit}"
+ check_freezer_state "${unit}" "running"
+ check_cgroup_state "$unit" 0
+ echo "[ OK ]"
+
+ echo -n " - CanFreeze(): "
+ output=$(dbus_can_freeze "${unit}")
+ [ "$output" = "b true" ]
+ echo "[ OK ]"
+
+ echo
+}
+
+test_jobs() {
+ local pid_before=
+ local pid_after=
+ echo "Test that it is possible to apply jobs on frozen units:"
+
+ systemctl start "${unit}"
+ dbus_freeze "${unit}"
+ check_freezer_state "${unit}" "frozen"
+
+ echo -n " - restart: "
+ pid_before=$(systemctl show -p MainPID "${unit}" --value)
+ systemctl restart "${unit}"
+ pid_after=$(systemctl show -p MainPID "${unit}" --value)
+ [ "$pid_before" != "$pid_after" ] && echo "[ OK ]"
+
+ dbus_freeze "${unit}"
+ check_freezer_state "${unit}" "frozen"
+
+ echo -n " - stop: "
+ timeout 5s systemctl stop "${unit}"
+ echo "[ OK ]"
+
+ echo
+}
+
+test_systemctl() {
+ echo "Test that systemctl freeze/thaw verbs:"
+
+ systemctl start "$unit"
+
+ echo -n " - freeze: "
+ systemctl freeze "$unit"
+ check_freezer_state "${unit}" "frozen"
+ check_cgroup_state "$unit" 1
+ # Freezing already frozen unit should be NOP and return quickly
+ timeout 3s systemctl freeze "$unit"
+ echo "[ OK ]"
+
+ echo -n " - thaw: "
+ systemctl thaw "$unit"
+ check_freezer_state "${unit}" "running"
+ check_cgroup_state "$unit" 0
+ # Likewise thawing already running unit shouldn't block
+ timeout 3s systemctl thaw "$unit"
+ echo "[ OK ]"
+
+ systemctl stop "$unit"
+
+ echo
+}
+
+test_systemctl_show() {
+ echo "Test systemctl show integration:"
+
+ systemctl start "$unit"
+
+ echo -n " - FreezerState property: "
+ state=$(systemctl show -p FreezerState --value "$unit")
+ [ "$state" = "running" ]
+ systemctl freeze "$unit"
+ state=$(systemctl show -p FreezerState --value "$unit")
+ [ "$state" = "frozen" ]
+ systemctl thaw "$unit"
+ echo "[ OK ]"
+
+ echo -n " - CanFreeze property: "
+ state=$(systemctl show -p CanFreeze --value "$unit")
+ [ "$state" = "yes" ]
+ echo "[ OK ]"
+
+ systemctl stop "$unit"
+ echo
+}
+
+test_recursive() {
+ local slice="bar.slice"
+ local unit="baz.service"
+
+ systemd-run --unit "$unit" --slice "$slice" sleep 3600 >/dev/null 2>&1
+
+ echo "Test recursive freezing:"
+
+ echo -n " - freeze: "
+ systemctl freeze "$slice"
+ check_freezer_state "${slice}" "frozen"
+ check_freezer_state "${unit}" "frozen"
+ grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events
+ grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+ echo "[ OK ]"
+
+ echo -n " - thaw: "
+ systemctl thaw "$slice"
+ check_freezer_state "${unit}" "running"
+ check_freezer_state "${slice}" "running"
+ grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events
+ grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+ echo "[ OK ]"
+
+ systemctl stop "$unit"
+ systemctl stop "$slice"
+
+ echo
+}
+
+test_preserve_state() {
+ local slice="bar.slice"
+ local unit="baz.service"
+
+ systemd-run --unit "$unit" --slice "$slice" sleep 3600 >/dev/null 2>&1
+
+ echo "Test that freezer state is preserved when recursive freezing is initiated from outside (e.g. by manager up the tree):"
+
+ echo -n " - freeze from outside: "
+ echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+
+ # Our state should not be affected
+ check_freezer_state "${slice}" "running"
+ check_freezer_state "${unit}" "running"
+
+ # However actual kernel state should be frozen
+ grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events
+ grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+ echo "[ OK ]"
+
+ echo -n " - thaw from outside: "
+ echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+ check_freezer_state "${unit}" "running"
+ check_freezer_state "${slice}" "running"
+ grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events
+ grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events
+ echo "[ OK ]"
+
+ echo -n " - thaw from outside while inner service is frozen: "
+ systemctl freeze "$unit"
+ check_freezer_state "${unit}" "frozen"
+ echo 1 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+ echo 0 > /sys/fs/cgroup/"${slice}"/cgroup.freeze
+ check_freezer_state "${slice}" "running"
+ check_freezer_state "${unit}" "frozen"
+ echo "[ OK ]"
+
+ systemctl stop "$unit"
+ systemctl stop "$slice"
+
+ echo
+}
+
+test -e /sys/fs/cgroup/system.slice/cgroup.freeze && {
+ start_test_service
+ test_dbus_api
+ test_systemctl
+ test_systemctl_show
+ test_jobs
+ test_recursive
+ test_preserve_state
+}
+
+echo OK > /testok
+exit 0
['systemd-nspawn.conf', 'ENABLE_MACHINED'],
['systemd-tmp.conf', ''],
['portables.conf', 'ENABLE_PORTABLED'],
+ ['systemd-pstore.conf', 'ENABLE_PSTORE'],
['tmp.conf', ''],
['x11.conf', ''],
['legacy.conf', 'HAVE_SYSV_COMPAT'],
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# The systemd-pstore.service(1) archives the contents of /sys/fs/pstore
+# upon boot so that there is room for a subsequent dump. This service
+# is enabled with:
+# systemctl enable systemd-pstore
+#
+# With the service enabled, the kernel still needs to be configured
+# to write data into the pstore. The kernel has two parameters,
+# crash_kexec_post_notifiers and printk.always_kmsg_dump, that
+# control writes into pstore.
+#
+# The crash_kexec_post_notifiers parameter enables the kernel to write
+# dmesg (including stack trace) into pstore upon a panic, and
+# printk.always_kmsg_dump parameter enables the kernel to write dmesg
+# upon a normal shutdown (shutdown, reboot, halt).
+#
+# To configure the kernel parameters, uncomment the appropriate
+# line(s) below. The value written is either 'Y' to enable the
+# kernel parameter, or 'N' to disable the kernel parameter.
+#
+# After making a change to this file, do:
+# systemd-tmpfiles --create path/to/tmpfiles.d/systemd-pstore.conf
+#
+# These changes are automatically applied on future re-boots.
+
+d /var/lib/systemd/pstore 0755 root root 14d
+#w /sys/module/printk/parameters/always_kmsg_dump - - - - Y
+w /sys/module/kernel/parameters/crash_kexec_post_notifiers - - - - Y
from xml_helper import xml_parse, xml_print, tree
from copy import deepcopy
-TEMPLATE = '''\
-<refentry id="systemd.directives" conditional="HAVE_PYTHON">
-
- <refentryinfo>
- <title>systemd.directives</title>
- <productname>systemd</productname>
- </refentryinfo>
-
- <refmeta>
- <refentrytitle>systemd.directives</refentrytitle>
- <manvolnum>7</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname>systemd.directives</refname>
- <refpurpose>Index of configuration directives</refpurpose>
- </refnamediv>
-
- <refsect1>
- <title>Unit directives</title>
-
- <para>Directives for configuring units, used in unit
- files.</para>
-
- <variablelist id='unit-directives' />
- </refsect1>
-
- <refsect1>
- <title>Options on the kernel command line</title>
-
- <para>Kernel boot options for configuring the behaviour of the
- systemd process.</para>
-
- <variablelist id='kernel-commandline-options' />
- </refsect1>
-
- <refsect1>
- <title>Environment variables</title>
-
- <para>Environment variables understood by the systemd manager
- and other programs and environment variable-compatible settings.</para>
-
- <variablelist id='environment-variables' />
- </refsect1>
-
- <refsect1>
- <title>EFI variables</title>
-
- <para>EFI variables understood by
- <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
- and other programs.</para>
-
- <variablelist id='efi-variables' />
- </refsect1>
-
- <refsect1>
- <title>UDEV directives</title>
-
- <para>Directives for configuring systemd units through the
- udev database.</para>
-
- <variablelist id='udev-directives' />
- </refsect1>
-
- <refsect1>
- <title>Network directives</title>
-
- <para>Directives for configuring network links through the
- net-setup-link udev builtin and networks through
- systemd-networkd.</para>
-
- <variablelist id='network-directives' />
- </refsect1>
-
- <refsect1>
- <title>Journal fields</title>
-
- <para>Fields in the journal events with a well known meaning.</para>
-
- <variablelist id='journal-directives' />
- </refsect1>
-
- <refsect1>
- <title>PAM configuration directives</title>
-
- <para>Directives for configuring PAM behaviour.</para>
-
- <variablelist id='pam-directives' />
- </refsect1>
-
- <refsect1>
- <title><filename>/etc/crypttab</filename> and
- <filename>/etc/fstab</filename> options</title>
-
- <para>Options which influence mounted filesystems and
- encrypted volumes.</para>
-
- <variablelist id='fstab-options' />
- </refsect1>
-
- <refsect1>
- <title><citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- directives</title>
-
- <para>Directives for configuring systemd-nspawn containers.</para>
-
- <variablelist id='nspawn-directives' />
- </refsect1>
-
- <refsect1>
- <title>Program configuration options</title>
-
- <para>Directives for configuring the behaviour of the
- systemd process and other tools through configuration files.</para>
-
- <variablelist id='config-directives' />
- </refsect1>
-
- <refsect1>
- <title>Command line options</title>
-
- <para>Command-line options accepted by programs in the
- systemd suite.</para>
-
- <variablelist id='options' />
- </refsect1>
-
- <refsect1>
- <title>Constants</title>
-
- <para>Various constant used and/or defined by systemd.</para>
-
- <variablelist id='constants' />
- </refsect1>
-
- <refsect1>
- <title>Miscellaneous options and directives</title>
-
- <para>Other configuration elements which don't fit in
- any of the above groups.</para>
-
- <variablelist id='miscellaneous' />
- </refsect1>
-
- <refsect1>
- <title>Files and directories</title>
-
- <para>Paths and file names referred to in the
- documentation.</para>
-
- <variablelist id='filenames' />
- </refsect1>
-
- <refsect1>
- <title>D-Bus interfaces</title>
-
- <para>Interfaces exposed over D-Bus.</para>
-
- <variablelist id='dbus-interface' />
- </refsect1>
-
- <refsect1>
- <title>D-Bus methods</title>
-
- <para>Methods exposed in the D-Bus interface.</para>
-
- <variablelist id='dbus-method' />
- </refsect1>
-
- <refsect1>
- <title>D-Bus properties</title>
-
- <para>Properties exposed in the D-Bus interface.</para>
-
- <variablelist id='dbus-property' />
- </refsect1>
-
- <refsect1>
- <title>D-Bus signals</title>
-
- <para>Signals emitted in the D-Bus interface.</para>
-
- <variablelist id='dbus-signal' />
- </refsect1>
-
- <refsect1>
- <title>Colophon</title>
- <para id='colophon' />
- </refsect1>
-</refentry>
-'''
-
COLOPHON = '''\
This index contains {count} entries in {sections} sections,
referring to {pages} individual manual pages.
storfile[name.text].append((pagename, section))
formatting[name.text] = name
+ storfile = directive_groups['specifiers']
+ for name in t.iterfind(".//table[@class='specifiers']//entry/literal"):
+ if name.text[0] != '%' or name.getparent().text is not None:
+ continue
+ if name.attrib.get('index') == 'false':
+ continue
+ storfile[name.text].append((pagename, section))
+ formatting[name.text] = name
+ for name in t.iterfind(".//literal[@class='specifiers']"):
+ storfile[name.text].append((pagename, section))
+ formatting[name.text] = name
+
def _make_section(template, name, directives, formatting):
varlist = template.find(".//*[@id='{}']".format(name))
for varname, manpages in sorted(directives.items()):
return template
-def make_page(*xml_files):
+def make_page(template_path, xml_files):
"Extract directives from xml_files and return XML index tree."
- template = tree.fromstring(TEMPLATE)
+ template = xml_parse(template_path)
names = [vl.get('id') for vl in template.iterfind('.//variablelist')]
directive_groups = {name:collections.defaultdict(list)
for name in names}
if __name__ == '__main__':
with open(sys.argv[1], 'wb') as f:
- f.write(xml_print(make_page(*sys.argv[2:])))
+ template_path = sys.argv[2]
+ xml_files = sys.argv[3:]
+ xml = make_page(template_path, xml_files)
+ f.write(xml_print(xml))
import collections
import sys
+import os
import shlex
import subprocess
import io
-import pprint
from lxml import etree
PARSER = etree.XMLParser(no_network=True,
class NoCommand(Exception):
pass
-def find_command(lines):
- acc = []
- for num, line in enumerate(lines):
- # skip empty leading line
- if num == 0 and not line:
- continue
- cont = line.endswith('\\')
- if cont:
- line = line[:-1].rstrip()
- acc.append(line if not acc else line.lstrip())
- if not cont:
- break
- joined = ' '.join(acc)
- if not joined.startswith('$ '):
- raise NoCommand
- return joined[2:], lines[:num+1] + [''], lines[-1]
-
BORING_INTERFACES = [
'org.freedesktop.DBus.Peer',
'org.freedesktop.DBus.Introspectable',
return file.getvalue(), declarations, interfaces
def subst_output(document, programlisting):
- try:
- cmd, prefix_lines, footer = find_command(programlisting.text.splitlines())
- except NoCommand:
+ executable = programlisting.get('executable', None)
+ if executable is None:
+ # Not our thing
return
+ executable = programlisting.get('executable')
+ node = programlisting.get('node')
+ interface = programlisting.get('interface')
- only_interface = programlisting.get('interface', None)
-
- argv = shlex.split(cmd)
- argv += ['--xml']
+ argv = [f'{build_dir}/{executable}', f'--bus-introspect={interface}']
print(f'COMMAND: {shlex.join(argv)}')
- object_idx = argv.index('--object-path')
- object_path = argv[object_idx + 1]
-
try:
out = subprocess.check_output(argv, text=True)
- except subprocess.CalledProcessError:
- print('command failed, ignoring', file=sys.stderr)
+ except FileNotFoundError:
+ print(f'{executable} not found, ignoring', file=sys.stderr)
return
xml = etree.fromstring(out, parser=PARSER)
- new_text, declarations, interfaces = xml_to_text(object_path, xml, only_interface=only_interface)
-
- programlisting.text = '\n'.join(prefix_lines) + '\n' + new_text + footer
+ new_text, declarations, interfaces = xml_to_text(node, xml, only_interface=interface)
+ programlisting.text = '\n' + new_text + ' '
if declarations:
missing = check_documented(document, declarations)
if __name__ == '__main__':
pages = sys.argv[1:]
+ if pages[0].startswith('--build-dir='):
+ build_dir = pages[0].partition('=')[2]
+ pages = pages[1:]
+ else:
+ build_dir = 'build'
+
+ if not os.path.exists(f'{build_dir}/systemd'):
+ exit(f"{build_dir}/systemd doesn't exist. Use --build-dir=.")
+
for page in pages:
process(page)
return ' \\\n\t'.join(sorted(files) or '#')
MESON_HEADER = '''\
-# Do not edit. Generated by make-man-rules.py.
+# Do not edit. Generated by update-man-rules.py.
# Update with:
# ninja -C build man/update-man-rules
manpages = ['''
clang
perl
libpwquality-dev
+ fdisk
libfdisk-dev
libp11-kit-dev
- libssl-dev)
+ libssl-dev
+ libzstd-dev
+ zstd)
function info() {
echo -e "\033[33;1m$1\033[0m"
export PATH="$HOME/.local/bin/:$PATH"
# We use a subset of https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks instead of "undefined"
-# because our fuzzers crash with "pointer-overflow" and "float-cast-overflow":
-# https://github.com/systemd/systemd/pull/12771#issuecomment-502139157
+# because our fuzzers crash with "float-cast-overflow":
# https://github.com/systemd/systemd/pull/12812#issuecomment-502780455
# TODO: figure out what to do about unsigned-integer-overflow: https://github.com/google/oss-fuzz/issues/910
-export SANITIZER="address -fsanitize=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,unsigned-integer-overflow,vla-bound,vptr -fno-sanitize-recover=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr"
+export SANITIZER="address -fsanitize=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,pointer-overflow,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,unsigned-integer-overflow,vla-bound,vptr -fno-sanitize-recover=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,pointer-overflow,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr"
tools/oss-fuzz.sh
FUZZING_TYPE=${1:-regression}
wget -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/latest/download/fuzzit_Linux_x86_64
chmod +x fuzzit
-find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | xargs --verbose -n1 -I%FUZZER% ./fuzzit create job ${FUZZIT_ARGS} %FUZZER%-asan-ubsan out/%FUZZER% ${FUZZIT_ADDITIONAL_FILES}
+# Simple wrapper which retries given command up to three times if it fails
+_retry() {
+ local EC=1
+
+ for _ in {0..2}; do
+ if "$@"; then
+ EC=0
+ break
+ fi
+
+ sleep 1
+ done
+
+ return $EC
+}
+
+find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | while read -r fuzzer; do
+ _retry ./fuzzit create job ${FUZZIT_ARGS} ${fuzzer}-asan-ubsan out/${fuzzer} ${FUZZIT_ADDITIONAL_FILES}
+done
export SANITIZER="memory -fsanitize-memory-track-origins"
FUZZIT_ARGS="--type ${FUZZING_TYPE} --branch ${FUZZIT_BRANCH} --revision ${TRAVIS_COMMIT}"
tools/oss-fuzz.sh
-find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | xargs --verbose -n1 -I%FUZZER% ./fuzzit create job ${FUZZIT_ARGS} %FUZZER%-msan out/%FUZZER% ${FUZZIT_ADDITIONAL_FILES}
+find out/ -maxdepth 1 -name 'fuzz-*' -executable -type f -exec basename '{}' \; | while read -r fuzzer; do
+ _retry ./fuzzit create job ${FUZZIT_ARGS} ${fuzzer}-msan out/${fuzzer} ${FUZZIT_ADDITIONAL_FILES}
+done
['hibernate.target', 'ENABLE_HIBERNATE'],
['hybrid-sleep.target', 'ENABLE_HIBERNATE'],
['suspend-then-hibernate.target', 'ENABLE_HIBERNATE'],
- ['initrd-cleanup.service', ''],
- ['initrd-fs.target', ''],
- ['initrd-parse-etc.service', ''],
- ['initrd-root-device.target', ''],
- ['initrd-root-fs.target', ''],
- ['initrd-switch-root.service', ''],
- ['initrd-switch-root.target', ''],
- ['initrd-udevadm-cleanup-db.service', ''],
- ['initrd.target', ''],
+ ['initrd-cleanup.service', 'ENABLE_INITRD'],
+ ['initrd-fs.target', 'ENABLE_INITRD'],
+ ['initrd-parse-etc.service', 'ENABLE_INITRD'],
+ ['initrd-root-device.target', 'ENABLE_INITRD'],
+ ['initrd-root-fs.target', 'ENABLE_INITRD'],
+ ['initrd-switch-root.service', 'ENABLE_INITRD'],
+ ['initrd-switch-root.target', 'ENABLE_INITRD'],
+ ['initrd-udevadm-cleanup-db.service', 'ENABLE_INITRD'],
+ ['initrd.target', 'ENABLE_INITRD'],
['kexec.target', ''],
['ldconfig.service', 'ENABLE_LDCONFIG',
'sysinit.target.wants/'],
['systemd-user-sessions.service', 'HAVE_PAM',
'multi-user.target.wants/'],
['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE'],
- ['systemd-volatile-root.service', ''],
+ ['systemd-volatile-root.service', 'ENABLE_INITRD'],
['systemd-repart.service', 'ENABLE_REPART',
'sysinit.target.wants/ initrd-root-fs.target.wants/'],
['user-runtime-dir@.service', ''],
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-binfmt
+ExecStop=@rootlibexecdir@/systemd-binfmt --unregister
TimeoutSec=90s
# (at your option) any later version.
[Unit]
-Description=Login Service
+Description=User Login Management
Documentation=man:systemd-logind.service(8) man:logind.conf(5)
Documentation=https://www.freedesktop.org/wiki/Software/systemd/logind
Documentation=https://www.freedesktop.org/wiki/Software/systemd/multiseat
What=tmpfs
Where=/tmp
Type=tmpfs
-Options=mode=1777,strictatime,nosuid,nodev
+Options=mode=1777,strictatime,nosuid,nodev,size=10%,nr_inodes=400k