summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/workflows/ubuntu-build-check.sh2
-rw-r--r--.travis.yml187
-rw-r--r--NEWS8
-rw-r--r--docs/RANDOM_SEEDS.md2
-rw-r--r--hwdb.d/60-autosuspend.hwdb44
-rw-r--r--hwdb.d/70-mouse.hwdb2
-rw-r--r--hwdb.d/meson.build36
-rwxr-xr-xhwdb.d/parse_hwdb.py18
-rw-r--r--man/custom-html.xsl12
-rw-r--r--man/homectl.xml3
-rw-r--r--man/resolved.conf.xml59
-rw-r--r--man/systemd-makefs@.service.xml6
-rw-r--r--man/systemd-modules-load.service.xml13
-rw-r--r--man/systemd-resolved.service.xml18
-rw-r--r--man/systemd.exec.xml37
-rw-r--r--man/systemd.resource-control.xml4
-rw-r--r--meson.build2
-rw-r--r--rules.d/50-udev-default.rules.in3
-rw-r--r--rules.d/60-autosuspend.rules14
-rw-r--r--rules.d/60-serial.rules5
-rw-r--r--rules.d/61-autosuspend-manual.rules19
-rw-r--r--rules.d/meson.build10
-rw-r--r--src/analyze/analyze.c4
-rw-r--r--src/basic/dlfcn-util.h8
-rw-r--r--src/basic/log.c51
-rw-r--r--src/basic/log.h4
-rw-r--r--src/basic/memory-util.h1
-rw-r--r--src/basic/meson.build4
-rw-r--r--src/basic/selinux-util.c158
-rw-r--r--src/busctl/busctl.c4
-rw-r--r--src/cgls/cgls.c4
-rw-r--r--src/cgtop/cgtop.c4
-rw-r--r--src/core/dbus-cgroup.c164
-rw-r--r--src/core/dbus-execute.c71
-rw-r--r--src/core/dbus-manager.c38
-rw-r--r--src/core/emergency-action.c35
-rw-r--r--src/core/execute.c19
-rw-r--r--src/core/execute.h4
-rw-r--r--src/core/job.c51
-rw-r--r--src/core/job.h3
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c65
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/main.c7
-rw-r--r--src/core/manager.c127
-rw-r--r--src/core/manager.h6
-rw-r--r--src/core/namespace.c16
-rw-r--r--src/core/namespace.h4
-rw-r--r--src/core/org.freedesktop.systemd1.conf4
-rw-r--r--src/core/transaction.c8
-rw-r--r--src/coredump/coredumpctl.c4
-rw-r--r--src/delta/delta.c4
-rw-r--r--src/detect-virt/detect-virt.c4
-rw-r--r--src/dissect/dissect.c2
-rw-r--r--src/escape/escape.c4
-rw-r--r--src/home/homectl.c4
-rw-r--r--src/hostname/hostnamectl.c4
-rw-r--r--src/hostname/hostnamed.c5
-rw-r--r--src/hwdb/hwdb.c4
-rw-r--r--src/id128/id128.c4
-rw-r--r--src/journal-remote/journal-remote-main.c2
-rw-r--r--src/journal-remote/journal-upload.c2
-rw-r--r--src/journal/cat.c4
-rw-r--r--src/journal/journalctl.c4
-rw-r--r--src/libsystemd-network/dhcp-lease-internal.h3
-rw-r--r--src/libsystemd-network/network-internal.h4
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c2
-rw-r--r--src/libsystemd/sd-bus/bus-message.c13
-rw-r--r--src/libsystemd/sd-network/sd-network.c12
-rw-r--r--src/locale/localectl.c4
-rw-r--r--src/locale/localed.c9
-rw-r--r--src/locale/meson.build2
-rw-r--r--src/login/loginctl.c4
-rw-r--r--src/login/logind.c2
-rw-r--r--src/login/user-runtime-dir.c6
-rw-r--r--src/machine/machinectl.c4
-rw-r--r--src/network/networkctl.c91
-rw-r--r--src/network/networkd-dhcp-server.c2
-rw-r--r--src/network/networkd-dhcp6.c2
-rw-r--r--src/network/networkd-link.c27
-rw-r--r--src/nspawn/nspawn-mount.c4
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/nss-systemd/nss-systemd.c71
-rw-r--r--src/nss-systemd/nss-systemd.h13
-rw-r--r--src/nss-systemd/nss-systemd.sym4
-rw-r--r--src/nss-systemd/userdb-glue.c52
-rw-r--r--src/portable/portablectl.c4
-rw-r--r--src/resolve/resolvectl.c4
-rw-r--r--src/resolve/resolved-dns-query.c19
-rw-r--r--src/resolve/resolved-dns-query.h2
-rw-r--r--src/resolve/resolved-dns-scope.c27
-rw-r--r--src/resolve/resolved-dns-scope.h2
-rw-r--r--src/resolve/resolved-gperf.gperf21
-rw-r--r--src/resolve/resolved-manager.h5
-rw-r--r--src/resolve/resolved.c2
-rw-r--r--src/resolve/resolved.conf.in1
-rw-r--r--src/shared/bus-unit-util.c41
-rw-r--r--src/shared/dissect-image.c37
-rw-r--r--src/shared/dissect-image.h2
-rw-r--r--src/shared/userdb.c205
-rw-r--r--src/shared/userdb.h3
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/systemd/sd-network.h10
-rw-r--r--src/sysusers/sysusers.c2
-rw-r--r--src/test/test-chase-symlinks.c4
-rw-r--r--src/test/test-namespace.c4
-rw-r--r--src/test/test-ns.c4
-rw-r--r--src/timedate/timedatectl.c4
-rw-r--r--src/timedate/timedated.c5
-rw-r--r--src/tmpfiles/tmpfiles.c4
-rw-r--r--src/udev/udevadm.c5
-rw-r--r--src/udev/udevd.c2
-rw-r--r--src/update-done/update-done.c4
-rw-r--r--src/user-sessions/user-sessions.c4
-rw-r--r--src/userdb/userdbctl.c4
-rw-r--r--src/userdb/userwork.c5
-rw-r--r--src/xdg-autostart-generator/xdg-autostart-service.c12
-rwxr-xr-xtest/TEST-21-SYSUSERS/test.sh4
-rw-r--r--test/TEST-52-HONORFIRSTSHUTDOWN/Makefile16
-rwxr-xr-xtest/TEST-52-HONORFIRSTSHUTDOWN/fini.sh10
-rwxr-xr-xtest/TEST-52-HONORFIRSTSHUTDOWN/test.sh19
-rw-r--r--test/fuzz/fuzz-bus-message/zero-offset-to-null-pointerbin0 -> 64 bytes
-rw-r--r--test/fuzz/fuzz-unit-file/directives.service2
-rw-r--r--test/meson.build2
-rw-r--r--test/test-functions2
-rwxr-xr-xtest/testsuite-52.units/testsuite-52.service6
-rwxr-xr-xtest/testsuite-52.units/testsuite-52.sh18
-rw-r--r--test/units/test-honor-first-shutdown.service11
-rwxr-xr-xtest/units/test-honor-first-shutdown.sh3
-rwxr-xr-xtools/make-autosuspend-rules.py24
-rwxr-xr-xtravis-ci/managers/debian.sh34
-rwxr-xr-xtravis-ci/managers/fedora.sh84
132 files changed, 1357 insertions, 1083 deletions
diff --git a/.github/workflows/ubuntu-build-check.sh b/.github/workflows/ubuntu-build-check.sh
index fb7c71ecb8..75fc36fffb 100755
--- a/.github/workflows/ubuntu-build-check.sh
+++ b/.github/workflows/ubuntu-build-check.sh
@@ -102,7 +102,7 @@ for args in "${ARGS[@]}"; do
SECONDS=0
info "Checking build with $args"
- if ! AR="$AR" CC="$CC" CXX="$CXX" meson -Dtests=unsafe -Dslow-tests=true --werror $args build; then
+ if ! AR="$AR" CC="$CC" CXX="$CXX" CFLAGS="-Werror" CXXFLAGS="-Werror" meson -Dtests=unsafe -Dslow-tests=true --werror $args build; then
fatal "meson failed with $args"
fi
diff --git a/.travis.yml b/.travis.yml
index d933ccce06..a72e81552f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,127 +1,82 @@
-sudo: required
+---
+# vi: ts=2 sw=2 et:
+
+language: bash
dist: bionic
services:
- - docker
+ - docker
env:
- global:
- - AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
- - CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
- - CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools"
- - REPO_ROOT="$TRAVIS_BUILD_DIR"
+ global:
+ - AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
+ - CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
+ - CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools"
+ - REPO_ROOT="$TRAVIS_BUILD_DIR"
+ jobs:
+ - DEBIAN_RELEASE=testing PHASE="RUN_GCC"
+ - DEBIAN_RELEASE=testing PHASE="RUN_GCC_ASAN_UBSAN"
+ - DEBIAN_RELEASE=testing PHASE="RUN_CLANG"
+ - DEBIAN_RELEASE=testing PHASE="RUN_CLANG_ASAN_UBSAN"
stages:
- - name: Build & test
- if: type != cron
+ # 'Test' is the default stage (for matrix jobs)
+ - name: Test
+ if: type != cron
# Run Coverity periodically instead of for each commit/PR
- - name: Coverity
- if: type = cron
-
-jobs:
- include:
- - stage: Build & test
- name: Debian Testing
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN || travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
+ - name: Coverity
+ if: type = cron
- - name: Debian Testing (ASan+UBSan)
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN_ASAN || travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
+# Matrix job definition - this is run for each combination of env variables
+# from the env.jobs array above
+before_install:
+ - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+ - docker --version
+install:
+ - $CI_MANAGERS/debian.sh SETUP
+script:
+ - $CI_MANAGERS/debian.sh $PHASE || travis_terminate 1
+after_script:
+ - $CI_MANAGERS/debian.sh CLEANUP
- - name: Debian Testing (clang)
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN_CLANG || travis-travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
-
- - name: Debian Testing (clang ASan+UBSan)
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN_CLANG_ASAN || travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
-
- - stage: Coverity
- language: bash
- env:
- - FEDORA_RELEASE="latest"
- - CONT_NAME="coverity-fedora-$FEDORA_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- - TOOL_BASE="/var/tmp/coverity-scan-analysis"
- - DOCKER_RUN="docker run -v $TOOL_BASE:$TOOL_BASE:rw --env-file .cov-env"
- # Coverity env variables
- - PLATFORM="$(uname)"
- - TOOL_ARCHIVE="/var/tmp/cov-analysis-$PLATFORM.tgz"
- - SCAN_URL="https://scan.coverity.com"
- - UPLOAD_URL="https://scan.coverity.com/builds"
- - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
- - COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
- - COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
- # Encrypted COVERITY_SCAN_TOKEN env variable
- # Generated using `travis encrypt -r systemd/systemd COVERITY_SCAN_TOKEN=xxxx`
- - secure: "jKSz+Y1Mv8xMpQHh7g5lzW7E6HQGndFz/vKDJQ1CVShwFoyjV3Zu+MFS3UYKlh1236zL0Z4dvsYFx/b3Hq8nxZWCrWeZs2NdXgy/wh8LZhxwzcGYigp3sIA/cYdP5rDjFJO0MasNkl25/rml8+eZWz+8/xQic98UQHjSco/EOWtssoRcg0J0c4eDM7bGLfIQWE73NNY1Q1UtWjKmx1kekVrM8dPmHXJ9aERka7bmcbJAcKd6vabs6DQ5AfWccUPIn/EsRYqIJTRxJrFYU6XizANZ1a7Vwk/DWHZUEn2msxcZw5BbAMDTMx0TbfrNkKSHMHuvQUCu6KCBAq414i+LgkMfmQ2SWwKiIUsud1kxXX3ZPl9bxDv1HkvVdcniC/EM7lNEEVwm4meOnjuhI2lhOyOjmP3FTSlMHGP7xlK8DS2k9fqL58vn0BaSjwWgd+2+HuL2+nJmxcK1eLGzKqaostFxrk2Xs2vPZkUdV2nWY/asUrcWHml6YlWDn2eP83pfwxHYsMiEHY/rTKvxeVY+iirO/AphoO+eaYu7LvjKZU1Yx5Z4u/SnGWAiCH0yhMis0bWmgi7SCbw+sDd2uya+aoiLIGiB2ChW7hXHXCue/dif6/gLU7b+L8R00pQwnWdvKUPoIJCmZJYCluTeib4jpW+EmARB2+nR8wms2K9FGKM="
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- # Install Coverity on the host
- - $CI_TOOLS/get-coverity.sh
- # Export necessary env variables for Coverity
- - env | grep -E "TRAVIS|COV|TOOL|URL" > .cov-env
- # Pull a Docker image and start a new container
- - $CI_MANAGERS/fedora.sh SETUP
- script:
- - set -e
- # Preconfigure with meson to prevent Coverity from capturing meson metadata
- - $DOCKER_EXEC meson cov-build -Dman=false
- # Run Coverity
- - $DOCKER_EXEC tools/coverity.sh build
- - $DOCKER_EXEC tools/coverity.sh upload
+# Inject another (single) job into the matrix for Coverity
+jobs:
+ include:
+ - stage: Coverity
+ language: bash
+ env:
+ - FEDORA_RELEASE="latest"
+ - TOOL_BASE="/var/tmp/coverity-scan-analysis"
+ - DOCKER_RUN="docker run -v $TOOL_BASE:$TOOL_BASE:rw --env-file .cov-env"
+ # Coverity env variables
+ - PLATFORM="$(uname)"
+ - TOOL_ARCHIVE="/var/tmp/cov-analysis-$PLATFORM.tgz"
+ - SCAN_URL="https://scan.coverity.com"
+ - UPLOAD_URL="https://scan.coverity.com/builds"
+ - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
+ - COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
+ - COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
+ # Encrypted COVERITY_SCAN_TOKEN env variable
+ # Generated using `travis encrypt -r systemd/systemd COVERITY_SCAN_TOKEN=xxxx`
+ - secure: "jKSz+Y1Mv8xMpQHh7g5lzW7E6HQGndFz/vKDJQ1CVShwFoyjV3Zu+MFS3UYKlh1236zL0Z4dvsYFx/b3Hq8nxZWCrWeZs2NdXgy/wh8LZhxwzcGYigp3sIA/cYdP5rDjFJO0MasNkl25/rml8+eZWz+8/xQic98UQHjSco/EOWtssoRcg0J0c4eDM7bGLfIQWE73NNY1Q1UtWjKmx1kekVrM8dPmHXJ9aERka7bmcbJAcKd6vabs6DQ5AfWccUPIn/EsRYqIJTRxJrFYU6XizANZ1a7Vwk/DWHZUEn2msxcZw5BbAMDTMx0TbfrNkKSHMHuvQUCu6KCBAq414i+LgkMfmQ2SWwKiIUsud1kxXX3ZPl9bxDv1HkvVdcniC/EM7lNEEVwm4meOnjuhI2lhOyOjmP3FTSlMHGP7xlK8DS2k9fqL58vn0BaSjwWgd+2+HuL2+nJmxcK1eLGzKqaostFxrk2Xs2vPZkUdV2nWY/asUrcWHml6YlWDn2eP83pfwxHYsMiEHY/rTKvxeVY+iirO/AphoO+eaYu7LvjKZU1Yx5Z4u/SnGWAiCH0yhMis0bWmgi7SCbw+sDd2uya+aoiLIGiB2ChW7hXHXCue/dif6/gLU7b+L8R00pQwnWdvKUPoIJCmZJYCluTeib4jpW+EmARB2+nR8wms2K9FGKM="
+ before_install:
+ - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+ - docker --version
+ install:
+ # Install Coverity on the host
+ - $CI_TOOLS/get-coverity.sh
+ # Export necessary env variables for Coverity
+ - env | grep -E "TRAVIS|COV|TOOL|URL" > .cov-env
+ # Pull a Docker image and start a new container
+ - $CI_MANAGERS/fedora.sh SETUP
+ script:
+ - set -e
+ # Preconfigure with meson to prevent Coverity from capturing meson metadata
+ - $DOCKER_EXEC meson cov-build -Dman=false
+ # Run Coverity
+ - $DOCKER_EXEC tools/coverity.sh build
+ - $DOCKER_EXEC tools/coverity.sh upload
- - set +e
- after_script:
- - $CI_MANAGERS/fedora.sh CLEANUP
+ - set +e
+ after_script:
+ - $CI_MANAGERS/fedora.sh CLEANUP
diff --git a/NEWS b/NEWS
index 7db370516a..8d93d0c813 100644
--- a/NEWS
+++ b/NEWS
@@ -87,6 +87,12 @@ CHANGES WITH 246 in spe:
used, the DNS-over-TLS certificate is validated to match the
specified hostname.
+ * systemd-resolved may be configured to forward single-label DNS names.
+ This is not standard-conformant, but may make sense in setups where
+ public DNS servers are not used.
+
+ * systemd-resolved's DNS-over-TLS support gained SNI validation.
+
* The fs.suid_dumpable sysctl is set to 2 / "suidsafe". This allows
systemd-coredump to save core files for suid processes. When saving
the core file, systemd-coredump will use the effective uid and gid of
@@ -538,8 +544,6 @@ CHANGES WITH 245:
* systemd-sysusers gained support for creating users with the primary
group named differently than the user.
- * systemd-resolved's DNS-over-TLS support gained SNI validation.
-
* systemd-growfs (i.e. the x-systemd.growfs mount option in /etc/fstab)
gained support for growing XFS partitions. Previously it supported
only ext4 and btrfs partitions.
diff --git a/docs/RANDOM_SEEDS.md b/docs/RANDOM_SEEDS.md
index d3b68e967a..c1735b1ac9 100644
--- a/docs/RANDOM_SEEDS.md
+++ b/docs/RANDOM_SEEDS.md
@@ -118,7 +118,7 @@ requires random numbers as well, including for the following uses:
* systemd maintains various hash tables internally. In order to harden them
against [collision
- attacks](https://rt.perl.org/Public/Bug/Display.html?CSRF_Token=165691af9ddaa95f653402f1b68de728)
+ attacks](https://www.cs.auckland.ac.nz/~mcw/Teaching/refs/misc/denial-of-service.pdf)
they are seeded with random numbers.
* At various places systemd needs random bytes for temporary file name
diff --git a/hwdb.d/60-autosuspend.hwdb b/hwdb.d/60-autosuspend.hwdb
new file mode 100644
index 0000000000..0de49afa6c
--- /dev/null
+++ b/hwdb.d/60-autosuspend.hwdb
@@ -0,0 +1,44 @@
+# This file is part of systemd.
+#
+# The lookup keys are $MODALIAS strings, see udev's hwdb builtin.
+#
+# Match string formats:
+# <subsystem>:<modalias>
+#
+# pci:v<vendor>d<device>
+# usb:v<vendor>p<product>
+#
+# To add local entries, create a new file
+# /etc/udev/hwdb.d/61-autosuspend-local.hwdb
+# and add your rules there. To load the new rules execute (as root):
+# systemd-hwdb update
+# udevadm trigger /dev/…
+#
+# If your changes are generally applicable, preferably send them as a pull
+# request to
+# https://github.com/systemd/systemd
+# or create a bug report on https://github.com/systemd/systemd/issues and
+# include your new rules, a description of the device, and the output of
+# udevadm info
+# the device.
+#
+# Allowed properties are:
+# ID_AUTOSUSPEND=1
+
+#
+# Sort by brand, model
+
+#########################################
+# Alcor
+#########################################
+
+# AU9540 Smartcard Reader
+usb:v058Fp9540*
+ ID_AUTOSUSPEND=1
+
+#########################################
+# Wacom
+#########################################
+
+usb:v056Ap51A0*
+ ID_AUTOSUSPEND=1
diff --git a/hwdb.d/70-mouse.hwdb b/hwdb.d/70-mouse.hwdb
index ef5a473e87..63ef1fba12 100644
--- a/hwdb.d/70-mouse.hwdb
+++ b/hwdb.d/70-mouse.hwdb
@@ -349,6 +349,8 @@ mouse:usb:v046dpc068:name:Logitech G500:
mouse:usb:v046dpc332:name:Logitech Gaming Mouse G502:
# Logitech G502 HERO SE
mouse:usb:v046dpc08b:name:Logitech G502 HERO SE:
+# Logitech G502 Hero
+mouse:usb:v046dpc08b:name:Logitech G502 HERO Gaming Mouse:
MOUSE_DPI=1200@1000 *2400@1000 3200@1000 6400@1000
# Logitech G700 Laser Mouse (Wired)
diff --git a/hwdb.d/meson.build b/hwdb.d/meson.build
index 4df6dabf89..5c77387a26 100644
--- a/hwdb.d/meson.build
+++ b/hwdb.d/meson.build
@@ -1,6 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1+
-hwdb_files = files('''
+# Those files right now are not supported by the grammar. Also,
+# they are very long but quite repetitive and the parser is not very fast.
+# So we don't "test" them.
+hwdb_files_notest = files('''
20-pci-vendor-model.hwdb
20-pci-classes.hwdb
20-usb-vendor-model.hwdb
@@ -12,6 +15,10 @@ hwdb_files = files('''
20-OUI.hwdb
20-net-ifname.hwdb
20-vmbus-class.hwdb
+'''.split())
+
+hwdb_files_test = files('''
+ 60-autosuspend.hwdb
60-evdev.hwdb
60-input-id.hwdb
60-keyboard.hwdb
@@ -23,7 +30,16 @@ hwdb_files = files('''
'''.split())
if conf.get('ENABLE_HWDB') == 1
- install_data(hwdb_files,
+ auto_suspend_rules = custom_target(
+ '60-autosuspend-chromiumos.hwdb',
+ output : '60-autosuspend-chromiumos.hwdb',
+ command : make_autosuspend_rules_py,
+ capture : true,
+ install : true,
+ install_dir: udevhwdbdir)
+
+ install_data(hwdb_files_notest,
+ hwdb_files_test,
install_dir : udevhwdbdir)
meson.add_install_script('sh', '-c',
@@ -32,15 +48,15 @@ if conf.get('ENABLE_HWDB') == 1
meson.add_install_script('sh', '-c',
'test -n "$DESTDIR" || @0@/systemd-hwdb update'
.format(rootbindir))
-endif
-
-############################################################
-parse_hwdb_py = find_program('parse_hwdb.py')
-if want_tests != 'false'
- test('parse-hwdb',
- parse_hwdb_py,
- timeout : 90)
+ if want_tests != 'false'
+ parse_hwdb_py = find_program('parse_hwdb.py')
+ test('parse-hwdb',
+ parse_hwdb_py,
+ args : [hwdb_files_test,
+ auto_suspend_rules],
+ timeout : 90)
+ endif
endif
############################################################
diff --git a/hwdb.d/parse_hwdb.py b/hwdb.d/parse_hwdb.py
index abef56728f..8e1b5fdafa 100755
--- a/hwdb.d/parse_hwdb.py
+++ b/hwdb.d/parse_hwdb.py
@@ -59,6 +59,7 @@ REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER))
SIGNED_REAL = Combine(Optional(Word('-+')) + REAL)
UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
+# Those patterns are used in type-specific matches
TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'),
'evdev': ('name', 'atkbd', 'input'),
'id-input': ('modalias'),
@@ -68,13 +69,27 @@ TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'),
'sensor': ('modalias', ),
}
+# Patterns that are used to set general properties on a device
+GENERAL_MATCHES = {'acpi',
+ 'bluetooth',
+ 'usb',
+ 'pci',
+ 'sdio',
+ 'vmbus',
+ 'OUI',
+ }
+
@lru_cache()
def hwdb_grammar():
ParserElement.setDefaultWhitespaceChars('')
prefix = Or(category + ':' + Or(conn) + ':'
for category, conn in TYPES.items())
- matchline = Combine(prefix + Word(printables + ' ' + '®')) + EOL
+
+ matchline_typed = Combine(prefix + Word(printables + ' ' + '®'))
+ matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables))
+ matchline = (matchline_typed | matchline_general) + EOL
+
propertyline = (White(' ', exact=1).suppress() +
Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.!-;, "') - Optional(pythonStyleComment)) +
EOL)
@@ -102,6 +117,7 @@ def property_grammar():
('MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL', INTEGER),
('MOUSE_WHEEL_CLICK_COUNT', INTEGER),
('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', INTEGER),
+ ('ID_AUTOSUSPEND', Literal('1')),
('ID_INPUT', Literal('1')),
('ID_INPUT_ACCELEROMETER', Literal('1')),
('ID_INPUT_JOYSTICK', Literal('1')),
diff --git a/man/custom-html.xsl b/man/custom-html.xsl
index 7eebfdb5a1..57a9cc97d2 100644
--- a/man/custom-html.xsl
+++ b/man/custom-html.xsl
@@ -19,7 +19,8 @@
<xsl:template match="citerefentry[not(@project)]">
<a>
<xsl:attribute name="href">
- <xsl:value-of select="refentrytitle"/><xsl:text>.html#</xsl:text>
+ <xsl:value-of select="refentrytitle"/>
+ <xsl:text>.html#</xsl:text>
<xsl:value-of select="refentrytitle/@target"/>
</xsl:attribute>
<xsl:call-template name="inline.charseq"/>
@@ -133,6 +134,15 @@
</a>
</xsl:template>
+<xsl:template match="citerefentry[@project='url']">
+ <a>
+ <xsl:attribute name="href">
+ <xsl:value-of select="refentrytitle/@url"/>
+ </xsl:attribute>
+ <xsl:call-template name="inline.charseq"/>
+ </a>
+</xsl:template>
+
<!--
- helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
- this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value)
diff --git a/man/homectl.xml b/man/homectl.xml
index 14877a0cde..3a4c6e5f5b 100644
--- a/man/homectl.xml
+++ b/man/homectl.xml
@@ -268,7 +268,8 @@
independently, for example with <citerefentry
project='man-pages'><refentrytitle>groupadd</refentrytitle><manvolnum>8</manvolnum></citerefentry>. If
non-existent groups that are listed there are ignored. This option may be used more than once, in
- which case all specified group lists are combined.</para></listitem>
+ which case all specified group lists are combined. If the user is currently a member of a group
+ which is not listed, the user will be removed from the group.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
index 9be41baaa5..0e9b90c1cd 100644
--- a/man/resolved.conf.xml
+++ b/man/resolved.conf.xml
@@ -67,20 +67,28 @@
<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 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
- are configured in it. This setting defaults to the empty list.</para>
-
- <para>Specified domain names may optionally be prefixed with <literal>~</literal>. In this case they do not
- define a search path, but preferably direct DNS queries for the indicated domains to the DNS servers configured
- with the system <varname>DNS=</varname> setting (see above), in case additional, suitable per-link DNS servers
- are known. If no per-link DNS servers are known using the <literal>~</literal> syntax has no effect. Use the
- construct <literal>~.</literal> (which is composed of <literal>~</literal> to indicate a routing domain and
- <literal>.</literal> to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the
- system DNS server defined with <varname>DNS=</varname> preferably for all domains.</para></listitem>
+ <listitem><para>A space-separated list of domains optionally prefixed with <literal>~</literal>,
+ used for two distinct purposes described below. Defaults to the empty list.</para>
+
+ <para>Any domains <emphasis>not</emphasis> prefixed with <literal>~</literal> are used as search
+ suffixes when resolving single-label hostnames (domain names which contain no dot), in order to
+ qualify them into fully-qualified domain names (FQDNs). These "search domains" are strictly processed
+ in the order they are specified in, 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> with the <varname>search</varname> keyword are used instead, if
+ that file exists and any domains are configured in it.</para>
+
+ <para>The domains prefixed with <literal>~</literal> are called "routing domains". All domains listed
+ here (both search domains and routing domains after removing the <literal>~</literal> prefix) define
+ a search path that preferably directs DNS queries to this inteface. This search path has an effect
+ only when suitable per-link DNS servers are known. Such servers may be defined through the
+ <varname>DNS=</varname> setting (see above) and dynamically at run time, for example from DHCP
+ leases. If no per-link DNS servers are known, routing domains have no effect.</para>
+
+ <para>Use the construct <literal>~.</literal> (which is composed from <literal>~</literal> to
+ indicate a routing domain and <literal>.</literal> to indicate the DNS root domain that is the
+ implied suffix of all DNS domains) to use the DNS servers defined for this link preferably for all
+ domains.</para></listitem>
</varlistentry>
<varlistentry>
@@ -258,11 +266,28 @@
<varlistentry>
<term><varname>ReadEtcHosts=</varname></term>
- <listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default), the DNS stub resolver will read
- <filename>/etc/hosts</filename>, and try to resolve hosts or address by using the entries in the file before
- sending query to DNS servers.</para></listitem>
+ <listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default),
+ <command>systemd-resolved</command> will read <filename>/etc/hosts</filename>, and try to resolve
+ hosts or address by using the entries in the file before sending query to DNS servers.
+ </para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ResolveUnicastSingleLabel=</varname></term>
+ <listitem><para>Takes a boolean argument. When false (the default),
+ <command>systemd-resolved</command> will not resolve A and AAAA queries for single-label names over
+ classic DNS. Note that such names may still be resolved if search domains are specified (see
+ <varname>Domains=</varname> above), or using other mechanisms, in particular via LLMNR or from
+ <filename>/etc/hosts</filename>. When true, queries for single-label names will be forwarded to
+ global DNS servers even if no search domains are defined.
+ </para>
+
+ <para>This option is provided for compatibility with configurations where <emphasis>public DNS
+ servers are not used</emphasis>. Forwarding single-label names to servers not under your control is
+ not standard-conformant, see <ulink
+ url="https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/">IAB
+ Statement</ulink>, and may create a privacy and security risk.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/man/systemd-makefs@.service.xml b/man/systemd-makefs@.service.xml
index d07d90315a..9aa058588e 100644
--- a/man/systemd-makefs@.service.xml
+++ b/man/systemd-makefs@.service.xml
@@ -51,7 +51,8 @@
<para><filename>systemd-makefs</filename> knows very little about specific file
systems and swap devices, and after checking that the block device does not already
contain a file system or other content, it will execute binaries specific to
- each filesystem type (<filename>/sbin/mkfs.<replaceable>type</replaceable></filename>).</para>
+ each filesystem type (<filename>/sbin/mkfs.<replaceable>type</replaceable></filename>
+ or <filename>/sbin/mkswap</filename>).</para>
<para><filename>systemd-growfs</filename> knows very little about specific file
systems and swap devices, and will instruct the kernel to grow the mounted
@@ -61,8 +62,7 @@
number specific to each file system, so only certain types are supported.
Currently:
<citerefentry project='man-pages'><refentrytitle>ext4</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- btrfs (see
- <citerefentry project='man-pages'><refentrytitle>btrfs-man5</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+ <citerefentry project='url'><refentrytitle url='https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)'>btrfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>xfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<!-- yes, that's what the man page is called. -->
and dm-crypt partitions (see
diff --git a/man/systemd-modules-load.service.xml b/man/systemd-modules-load.service.xml
index ca9edef367..e960609c6c 100644
--- a/man/systemd-modules-load.service.xml
+++ b/man/systemd-modules-load.service.xml
@@ -29,14 +29,15 @@
<refsect1>
<title>Description</title>
- <para><filename>systemd-modules-load.service</filename> is an
- early boot service that loads kernel modules based on static
- configuration.</para>
+ <para><filename>systemd-modules-load.service</filename> is an early boot service that loads kernel
+ modules. It reads static configuration from files in <filename>/usr</filename> and
+ <filename>/etc</filename>, but also runtime configuration from <filename>/run</filename> and the kernel
+ command line (see below).</para>
<para>See
- <citerefentry><refentrytitle>modules-load.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for information about the configuration of this service.</para>
-
+ <citerefentry><refentrytitle>modules-load.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ information about the configuration format of this service and paths where configuration files can be
+ created.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
index 6e1ee9f4a5..914607e3f8 100644
--- a/man/systemd-resolved.service.xml
+++ b/man/systemd-resolved.service.xml
@@ -135,14 +135,16 @@
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>
+ MulticastDNS) for non-synthesized single-label names is allowed for non-top-level domains. This means
+ that such records can 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. Additionally, lookup of
+ single-label names via unicast DNS may be enabled with the
+ <varname>ResolveUnicastSingleLabel=yes</varname> setting. 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 by default, 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 servers if there are any. Note that by default, lookups for
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index f5db55511f..aa8a3f75bc 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -146,6 +146,43 @@
</varlistentry>
<varlistentry>
+ <term><varname>RootHash=</varname></term>
+
+ <listitem><para>Takes a data integrity (dm-verity) root hash specified in hexadecimal, or the path to a file
+ containing a root hash in ASCII hexadecimal format. This option enables data integrity checks using dm-verity,
+ if the used image contains the appropriate integrity data (see above) or if <varname>RootVerity=</varname> is used.
+ The specified hash must match the root hash of integrity data, and is usually at least 256 bits (and hence 64
+ formatted hexadecimal characters) long (in case of SHA256 for example). If this option is not specified, but
+ the image file carries the <literal>user.verity.roothash</literal> extended file attribute (see <citerefentry
+ project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry>), then the root
+ hash is read from it, also as formatted hexadecimal characters. If the extended file attribute is not found (or
+ is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
+ found next to the image file, bearing otherwise the same name (except if the image has the
+ <filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
+ is read from it and automatically used, also as formatted hexadecimal characters.</para>
+
+ <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>RootVerity=</varname></term>
+
+ <listitem><para>Takes the path to a data integrity (dm-verity) file. This option enables data integrity checks
+ using dm-verity, if <varname>RootImage=</varname> is used and a root-hash is passed and if the used image itself
+ does not contains the integrity data. The integrity data must be matched by the root hash. If this option is not
+ specified, but a file with the <filename>.verity</filename> suffix is found next to the image file, bearing otherwise
+ the same name (except if the image has the <filename>.raw</filename> suffix, in which case the verity data file must
+ not have it in its name), the verity data is read from it and automatically used.</para>
+
+ <para>This option is supported only for disk images that contain a single file system, without an enveloping partition
+ table. Images that contain a GPT partition table should instead include both root file system and matching Verity
+ data in the same image, implementing the
+ [Discoverable Partition Specification](https://systemd.io/DISCOVERABLE_PARTITIONS)</para>
+
+ <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>MountAPIVFS=</varname></term>
<listitem><para>Takes a boolean argument. If on, a private mount namespace for the unit's processes is created
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 6d3568576c..aa368732fb 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -670,8 +670,8 @@
</varlistentry>
<varlistentry>
- <term><varname>IPIngressFilterPath=<replaceable>BPF_FS_PROGRAMM_PATH</replaceable></varname></term>
- <term><varname>IPEgressFilterPath=<replaceable>BPF_FS_PROGRAMM_PATH</replaceable></varname></term>
+ <term><varname>IPIngressFilterPath=<replaceable>BPF_FS_PROGRAM_PATH</replaceable></varname></term>
+ <term><varname>IPEgressFilterPath=<replaceable>BPF_FS_PROGRAM_PATH</replaceable></varname></term>
<listitem>
<para>Add custom network traffic filters implemented as BPF programs, applying to all IP packets
diff --git a/meson.build b/meson.build
index 4a679449ce..8f1d1b5897 100644
--- a/meson.build
+++ b/meson.build
@@ -1660,7 +1660,7 @@ test_dlopen = executable(
build_by_default : want_tests != 'false')
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
- ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h'],
+ ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h src/nss-systemd/nss-systemd.h'],
['mymachines', 'ENABLE_NSS_MYMACHINES'],
['resolve', 'ENABLE_NSS_RESOLVE']]
diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in
index 50747a1988..cef78f9d68 100644
--- a/rules.d/50-udev-default.rules.in
+++ b/rules.d/50-udev-default.rules.in
@@ -10,8 +10,9 @@ SUBSYSTEM=="virtio-ports", KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-
SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb", GOTO="default_hwdb_imported"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
+LABEL="default_hwdb_imported"
ACTION!="add", GOTO="default_end"
diff --git a/rules.d/60-autosuspend.rules b/rules.d/60-autosuspend.rules
new file mode 100644
index 0000000000..1f9ebef631
--- /dev/null
+++ b/rules.d/60-autosuspend.rules
@@ -0,0 +1,14 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add", GOTO="autosuspend_end"
+
+# I2C rules
+SUBSYSTEM=="i2c", ATTR{name}=="cyapa", \
+ ATTR{power/control}="on", GOTO="autosuspend_end"
+
+# Enable autosuspend if hwdb says so. Here we are relying on
+# the hwdb import done earlier based on MODALIAS.
+ENV{ID_AUTOSUSPEND}=="1", TEST=="power/control", \
+ ATTR{power/control}="auto"
+
+LABEL="autosuspend_end"
diff --git a/rules.d/60-serial.rules b/rules.d/60-serial.rules
index f303e27fd5..b1626650b7 100644
--- a/rules.d/60-serial.rules
+++ b/rules.d/60-serial.rules
@@ -4,8 +4,9 @@ ACTION=="remove", GOTO="serial_end"
SUBSYSTEM!="tty", GOTO="serial_end"
SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
-SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
+# We already ran the hwdb builtin for devices with MODALIAS in 50-default.rules.
+# Let's cover the remaining case here, where we walk up the tree to find a node with $MODALIAS.
+ENV{MODALIAS}=="", SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
# /dev/serial/by-path/, /dev/serial/by-id/ for USB devices
KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="serial_end"
diff --git a/rules.d/61-autosuspend-manual.rules b/rules.d/61-autosuspend-manual.rules
deleted file mode 100644
index 2b973af960..0000000000
--- a/rules.d/61-autosuspend-manual.rules
+++ /dev/null
@@ -1,19 +0,0 @@
-# This udev rule is for any devices that should enter automatic suspend
-# but are not already included in generated rules from Chromium OS via
-# tools/make-autosuspend-rules.py
-#
-
-ACTION!="add", GOTO="autosuspend_manual_end"
-SUBSYSTEM!="usb", GOTO="autosuspend_manual_end"
-
-SUBSYSTEM=="usb", GOTO="autosuspend_manual_usb"
-
-# USB rules
-LABEL="autosuspend_manual_usb"
-GOTO="autosuspend_manual_end"
-
-# Enable autosuspend
-LABEL="autosuspend_manual_enable"
-TEST=="power/control", ATTR{power/control}="auto", GOTO="autosuspend_manual_end"
-
-LABEL="autosuspend_manual_end"
diff --git a/rules.d/meson.build b/rules.d/meson.build
index 13d1d330cf..ca4445d774 100644
--- a/rules.d/meson.build
+++ b/rules.d/meson.build
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1+
rules = files('''
+ 60-autosuspend.rules
60-block.rules
60-cdrom_id.rules
60-drm.rules
@@ -14,7 +15,6 @@ rules = files('''
60-persistent-v4l.rules
60-sensor.rules
60-serial.rules
- 61-autosuspend-manual.rules
70-joystick.rules
70-mouse.rules
70-touchpad.rules
@@ -45,11 +45,3 @@ foreach file : rules_in
install_dir : udevrulesdir)
all_rules += gen
endforeach
-
-auto_suspend_rules = custom_target(
- '60-autosuspend-chromiumos.rules',
- output : '60-autosuspend-chromiumos.rules',
- command : make_autosuspend_rules_py,
- capture : true,
- install : true,
- install_dir: [udevrulesdir])
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index faf50d2ac3..a8bd993cbe 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -2376,9 +2376,7 @@ static int run(int argc, char *argv[]) {
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/basic/dlfcn-util.h b/src/basic/dlfcn-util.h
new file mode 100644
index 0000000000..d254afb68b
--- /dev/null
+++ b/src/basic/dlfcn-util.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <dlfcn.h>
+
+#include "macro.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose);
diff --git a/src/basic/log.c b/src/basic/log.c
index ca024d970e..c6fe203808 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -7,6 +7,7 @@
#include <stdarg.h>
#include <stddef.h>
#include <sys/signalfd.h>
+#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/un.h>
@@ -219,6 +220,32 @@ fail:
return r;
}
+static bool stderr_is_journal(void) {
+ _cleanup_free_ char *w = NULL;
+ const char *e;
+ uint64_t dev, ino;
+ struct stat st;
+
+ e = getenv("JOURNAL_STREAM");
+ if (!e)
+ return false;
+
+ if (extract_first_word(&e, &w, ":", EXTRACT_DONT_COALESCE_SEPARATORS) <= 0)
+ return false;
+ if (!e)
+ return false;
+
+ if (safe_atou64(w, &dev) < 0)
+ return false;
+ if (safe_atou64(e, &ino) < 0)
+ return false;
+
+ if (fstat(STDERR_FILENO, &st) < 0)
+ return false;
+
+ return st.st_dev == dev && st.st_ino == ino;
+}
+
int log_open(void) {
int r;
@@ -238,9 +265,7 @@ int log_open(void) {
return 0;
}
- if (log_target != LOG_TARGET_AUTO ||
- getpid_cached() == 1 ||
- isatty(STDERR_FILENO) <= 0) {
+ if (log_target != LOG_TARGET_AUTO || getpid_cached() == 1 || stderr_is_journal()) {
if (!prohibit_ipc &&
IN_SET(log_target, LOG_TARGET_AUTO,
@@ -1121,16 +1146,20 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
}
void log_parse_environment_realm(LogRealm realm) {
- /* Do not call from library code. */
-
- const char *e;
-
if (getpid_cached() == 1 || get_ctty_devnr(0, NULL) < 0)
/* Only try to read the command line in daemons. We assume that anything that has a
* controlling tty is user stuff. For PID1 we do a special check in case it hasn't
* closed the console yet. */
(void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
+ log_parse_environment_cli_realm(realm);
+}
+
+void log_parse_environment_cli_realm(LogRealm realm) {
+ /* Do not call from library code. */
+
+ const char *e;
+
e = getenv("SYSTEMD_LOG_TARGET");
if (e && log_set_target_from_string(e) < 0)
log_warning("Failed to parse log target '%s'. Ignoring.", e);
@@ -1405,3 +1434,11 @@ void log_setup_service(void) {
log_parse_environment();
(void) log_open();
}
+
+void log_setup_cli(void) {
+ /* Sets up logging the way it is most appropriate for running a program as a CLI utility. */
+
+ log_show_color(true);
+ log_parse_environment_cli();
+ (void) log_open();
+}
diff --git a/src/basic/log.h b/src/basic/log.h
index 2c1b00fb88..15807d3029 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -84,8 +84,11 @@ void log_close(void);
void log_forget_fds(void);
void log_parse_environment_realm(LogRealm realm);
+void log_parse_environment_cli_realm(LogRealm realm);
#define log_parse_environment() \
log_parse_environment_realm(LOG_REALM)
+#define log_parse_environment_cli() \
+ log_parse_environment_cli_realm(LOG_REALM)
int log_dispatch_internal(
int level,
@@ -341,3 +344,4 @@ int log_syntax_invalid_utf8_internal(
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
void log_setup_service(void);
+void log_setup_cli(void);
diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h
index a6a2ccdbc2..4f596cffb7 100644
--- a/src/basic/memory-util.h
+++ b/src/basic/memory-util.h
@@ -13,6 +13,7 @@
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
+#define PAGE_OFFSET(l) ((l) & (page_size() - 1))
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 5bb49ef401..90924d6cb8 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -39,6 +39,7 @@ basic_sources = files('''
device-nodes.h
dirent-util.c
dirent-util.h
+ dlfcn-util.h
efivars.c
efivars.h
env-file.c
@@ -328,7 +329,8 @@ libbasic = static_library(
threads,
libcap,
libselinux,
- libm],
+ libm,
+ libdl],
c_args : ['-fvisibility=default'],
install : false)
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index 33ff427ae7..80bd65b155 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -39,7 +39,18 @@ static int cached_enforcing = -1;
static struct selabel_handle *label_hnd = NULL;
#define log_enforcing(...) log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
-#define log_enforcing_errno(r, ...) log_full_errno(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, r, __VA_ARGS__)
+
+#define log_enforcing_errno(error, ...) \
+ ({ \
+ bool _enforcing = mac_selinux_enforcing(); \
+ int _level = _enforcing ? LOG_ERR : LOG_WARNING; \
+ int _e = (error); \
+ \
+ int _r = (log_get_max_level() >= LOG_PRI(_level)) \
+ ? log_internal_realm(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
+ : -ERRNO_VALUE(_e); \
+ _enforcing ? _r : 0; \
+ })
#endif
bool mac_selinux_use(void) {
@@ -59,14 +70,15 @@ bool mac_selinux_enforcing(void) {
#if HAVE_SELINUX
if (_unlikely_(cached_enforcing < 0)) {
cached_enforcing = security_getenforce();
- if (cached_enforcing == -1)
- log_error_errno(errno, "Failed to get SELinux enforced status, continue in enforcing mode: %m");
- else
- log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive");
+ if (cached_enforcing < 0) {
+ log_debug_errno(errno, "Failed to get SELinux enforced status, continuing in enforcing mode: %m");
+ return true; /* treat failure as enforcing mode */
+ }
+
+ log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive");
}
- /* treat failure as enforcing mode */
- return (cached_enforcing != 0);
+ return cached_enforcing > 0;
#else
return false;
#endif
@@ -90,11 +102,11 @@ static int setenforce_callback(int enforcing) {
#endif
int mac_selinux_init(void) {
- int r = 0;
-
#if HAVE_SELINUX
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
+ char timespan[FORMAT_TIMESPAN_MAX];
+ int l;
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_callback);
@@ -109,25 +121,20 @@ int mac_selinux_init(void) {
before_timestamp = now(CLOCK_MONOTONIC);
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
- if (!label_hnd) {
- log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
- r = mac_selinux_enforcing() ? -errno : 0;
- } else {
- char timespan[FORMAT_TIMESPAN_MAX];
- int l;
+ if (!label_hnd)
+ return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
- after_timestamp = now(CLOCK_MONOTONIC);
- after_mallinfo = mallinfo();
+ after_timestamp = now(CLOCK_MONOTONIC);
+ after_mallinfo = mallinfo();
- l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
+ l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
- log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
- format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
- (l+1023)/1024);
- }
-#endif
+ log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
+ format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
+ (l+1023)/1024);
- return r;
+#endif
+ return 0;
}
void mac_selinux_finish(void) {
@@ -226,9 +233,7 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
return 0;
fail:
- log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
- if (mac_selinux_enforcing())
- return r;
+ return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
#endif
return 0;
@@ -243,21 +248,17 @@ int mac_selinux_apply(const char *path, const char *label) {
assert(path);
assert(label);
- if (setfilecon(path, label) < 0) {
- log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
- if (mac_selinux_enforcing())
- return -errno;
- }
+ if (setfilecon(path, label) < 0)
+ return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
#endif
return 0;
}
int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
- int r = -EOPNOTSUPP;
-
#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
security_class_t sclass;
+ int r;
assert(exe);
assert(label);
@@ -280,36 +281,39 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
r = security_compute_create_raw(mycon, fcon, sclass, label);
if (r < 0)
return -errno;
-#endif
- return r;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}
int mac_selinux_get_our_label(char **label) {
- int r = -EOPNOTSUPP;
+#if HAVE_SELINUX
+ int r;
assert(label);
-#if HAVE_SELINUX
if (!mac_selinux_use())
return -EOPNOTSUPP;
r = getcon_raw(label);
if (r < 0)
return -errno;
-#endif
- return r;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
- int r = -EOPNOTSUPP;
-
#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
security_class_t sclass;
const char *range = NULL;
+ int r;
assert(socket_fd >= 0);
assert(exe);
@@ -362,21 +366,19 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
r = security_compute_create_raw(mycon, fcon, sclass, label);
if (r < 0)
return -errno;
-#endif
- return r;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}
char* mac_selinux_free(char *label) {
#if HAVE_SELINUX
- if (!label)
- return NULL;
-
- if (!mac_selinux_use())
- return NULL;
-
freecon(label);
+#else
+ assert(!label);
#endif
return NULL;
@@ -399,26 +401,21 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
if (errno == ENOENT)
return 0;
- log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
- } else {
- if (setfscreatecon_raw(filecon) >= 0)
- return 0; /* Success! */
-
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
+ return log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
}
- if (mac_selinux_enforcing())
- return -errno;
+ if (setfscreatecon_raw(filecon) < 0)
+ return log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
return 0;
}
#endif
int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
- int r = 0;
-
#if HAVE_SELINUX
_cleanup_free_ char *abspath = NULL;
+ int r;
+
assert(path);
@@ -440,15 +437,16 @@ int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode)
return -ENOMEM;
}
- r = selinux_create_file_prepare_abspath(path, mode);
+ return selinux_create_file_prepare_abspath(path, mode);
+#else
+ return 0;
#endif
- return r;
}
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
- int r = 0;
-
#if HAVE_SELINUX
+ int r;
+
_cleanup_free_ char *abspath = NULL;
assert(path);
@@ -460,9 +458,10 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
if (r < 0)
return r;
- r = selinux_create_file_prepare_abspath(abspath, mode);
+ return selinux_create_file_prepare_abspath(abspath, mode);
+#else
+ return 0;
#endif
- return r;
}
void mac_selinux_create_file_clear(void) {
@@ -480,17 +479,13 @@ void mac_selinux_create_file_clear(void) {
int mac_selinux_create_socket_prepare(const char *label) {
#if HAVE_SELINUX
- if (!mac_selinux_use())
- return 0;
-
assert(label);
- if (setsockcreatecon(label) < 0) {
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
+ if (!mac_selinux_use())
+ return 0;
- if (mac_selinux_enforcing())
- return -errno;
- }
+ if (setsockcreatecon(label) < 0)
+ return log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
#endif
return 0;
@@ -561,15 +556,14 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
if (errno == ENOENT)
goto skipped;
- log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
- if (mac_selinux_enforcing())
- return -errno;
-
+ r = log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
+ if (r < 0)
+ return r;
} else {
if (setfscreatecon_raw(fcon) < 0) {
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
- if (mac_selinux_enforcing())
- return -errno;
+ r = log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
+ if (r < 0)
+ return r;
} else
context_changed = true;
}
@@ -577,7 +571,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
if (context_changed)
- setfscreatecon_raw(NULL);
+ (void) setfscreatecon_raw(NULL);
return r;
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 8e000ee119..3ab90de63e 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -2598,9 +2598,7 @@ static int busctl_main(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index b55d7299ca..939a391e21 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -164,9 +164,7 @@ static void show_cg_info(const char *controller, const char *path) {
static int run(int argc, char *argv[]) {
int r, output_flags;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index de25aaae5d..e6c09d1b38 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -908,9 +908,7 @@ static int run(int argc, char *argv[]) {
CGroupMask mask;
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 8587a712e2..080f6fb1ae 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -707,112 +707,14 @@ static int bus_cgroup_set_boolean(
return 1; \
}
-#define BUS_DEFINE_SET_CGROUP_PROTECTION(function, mask, scale) \
- static int bus_cgroup_set_##function( \
- Unit *u, \
- const char *name, \
- uint64_t *p, \
- bool *s, \
- sd_bus_message *message, \
- UnitWriteFlags flags, \
- sd_bus_error *error) { \
- \
- uint64_t v = CGROUP_LIMIT_MIN; \
- bool nonempty = true; \
- char type; \
- int r; \
- \
- assert(p); \
- assert(s); \
- \
- r = sd_bus_message_peek_type(message, &type, NULL); \
- if (r < 0) \
- return r; \
- if (type == SD_BUS_TYPE_BOOLEAN) { \
- r = sd_bus_message_read(message, "b", &nonempty); \
- if (r < 0) \
- return r; \
- /* Bool is used to denote empty value only */ \
- if (nonempty) \
- return -EINVAL; \
- } else if (type != SD_BUS_TYPE_UINT64) { \
- return -EINVAL; \
- } else { \
- r = sd_bus_message_read(message, "t", &v); \
- if (r < 0) \
- return r; \
- } \
- \
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
- *p = v; \
- unit_invalidate_cgroup(u, mask); \
- if (!nonempty) { \
- *s = false; \
- unit_write_settingf(u, flags, name, \
- "%s=", name); \
- } else if (v == CGROUP_LIMIT_MAX) { \
- *s = true; \
- unit_write_settingf(u, flags, name, \
- "%s=infinity", name); \
- } else { \
- *s = true; \
- unit_write_settingf(u, flags, name, \
- "%s=%" PRIu64, name, v); \
- } \
- } \
- \
- return 1; \
- } \
- static int bus_cgroup_set_##function##_scale( \
- Unit *u, \
- const char *name, \
- uint64_t *p, \
- bool *s, \
- sd_bus_message *message, \
- UnitWriteFlags flags, \
- sd_bus_error *error) { \
- \
- uint64_t v; \
- uint32_t raw; \
- int r; \
- \
- assert(p); \
- assert(s); \
- \
- r = sd_bus_message_read(message, "u", &raw); \
- if (r < 0) \
- return r; \
- \
- v = scale(raw, UINT32_MAX); \
- if (v >= UINT64_MAX) \
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
- "Value specified in %s is out of range", name); \
- \
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
- *p = v; \
- unit_invalidate_cgroup(u, mask); \
- \
- /* Prepare to chop off suffix */ \
- assert_se(endswith(name, "Scale")); \
- \
- uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
- unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
- (int)(strlen(name) - strlen("Scale")), name, \
- scaled / 10, scaled % 10); \
- } \
- \
- *s = true; \
- return 1; \
- }
-
DISABLE_WARNING_TYPE_LIMITS;
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1);
+BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
-BUS_DEFINE_SET_CGROUP_PROTECTION(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale);
REENABLE_WARNING;
static int bus_cgroup_set_tasks_max(
@@ -938,17 +840,33 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryAccounting"))
return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
- if (streq(name, "MemoryMin"))
- return bus_cgroup_set_memory_protection(u, name, &c->memory_min, &c->memory_min_set, message, flags, error);
+ if (streq(name, "MemoryMin")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
+ if (r > 0)
+ c->memory_min_set = true;
+ return r;
+ }
- if (streq(name, "MemoryLow"))
- return bus_cgroup_set_memory_protection(u, name, &c->memory_low, &c->memory_low_set, message, flags, error);
+ if (streq(name, "MemoryLow")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
+ if (r > 0)
+ c->memory_low_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryMin"))
- return bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error);
+ if (streq(name, "DefaultMemoryMin")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
+ if (r > 0)
+ c->default_memory_min_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryLow"))
- return bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error);
+ if (streq(name, "DefaultMemoryLow")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
+ if (r > 0)
+ c->default_memory_low_set = true;
+ return r;
+ }
if (streq(name, "MemoryHigh"))
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
@@ -962,17 +880,33 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryLimit"))
return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
- if (streq(name, "MemoryMinScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, &c->memory_min_set, message, flags, error);
+ if (streq(name, "MemoryMinScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
+ if (r > 0)
+ c->memory_min_set = true;
+ return r;
+ }
- if (streq(name, "MemoryLowScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, &c->memory_low_set, message, flags, error);
+ if (streq(name, "MemoryLowScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
+ if (r > 0)
+ c->memory_low_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryMinScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error);
+ if (streq(name, "DefaultMemoryMinScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
+ if (r > 0)
+ c->default_memory_min_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryLowScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error);
+ if (streq(name, "DefaultMemoryLowScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
+ if (r > 0)
+ c->default_memory_low_set = true;
+ return r;
+ }
if (streq(name, "MemoryHighScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 5b217c059d..68ce395c56 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -746,6 +746,25 @@ static int property_get_log_extra_fields(
return sd_bus_message_close_container(reply);
}
+static int property_get_root_hash(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(c);
+ assert(property);
+ assert(reply);
+
+ return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -788,6 +807,9 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1258,6 +1280,55 @@ int bus_exec_context_set_transient_property(
if (streq(name, "RootImage"))
return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
+ if (streq(name, "RootHash")) {
+ const void *roothash_decoded;
+ size_t roothash_decoded_size;
+
+ r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *encoded = NULL;
+
+ if (roothash_decoded_size == 0) {
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+
+ unit_write_settingf(u, flags, name, "RootHash=");
+ } else {
+ _cleanup_free_ void *p;
+
+ encoded = hexmem(roothash_decoded, roothash_decoded_size);
+ if (!encoded)
+ return -ENOMEM;
+
+ p = memdup(roothash_decoded, roothash_decoded_size);
+ if (!p)
+ return -ENOMEM;
+
+ free_and_replace(c->root_hash, p);
+ c->root_hash_size = roothash_decoded_size;
+ c->root_hash_path = mfree(c->root_hash_path);
+
+ unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
+ }
+ }
+
+ return 1;
+ }
+
+ if (streq(name, "RootHashPath")) {
+ c->root_hash_size = 0;
+ c->root_hash = mfree(c->root_hash);
+
+ return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
+ }
+
+ if (streq(name, "RootVerity"))
+ return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
+
if (streq(name, "RootDirectory"))
return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 2a3c8e776a..5cb06867cb 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -234,14 +234,12 @@ static int property_get_show_status(
sd_bus_error *error) {
Manager *m = userdata;
- int b;
+ assert(m);
assert(bus);
assert(reply);
- assert(m);
- b = IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
- return sd_bus_message_append_basic(reply, 'b', &b);
+ return sd_bus_message_append(reply, "b", manager_get_show_status_on(m));
}
static int property_get_runtime_watchdog(
@@ -311,7 +309,7 @@ static int property_set_watchdog(Manager *m, WatchdogType type, sd_bus_message *
if (r < 0)
return r;
- return manager_set_watchdog_overridden(m, type, timeout);
+ return manager_override_watchdog(m, type, timeout);
}
static int property_set_runtime_watchdog(
@@ -2452,6 +2450,30 @@ static int method_abandon_scope(sd_bus_message *message, void *userdata, sd_bus_
return bus_scope_method_abandon(message, u, error);
}
+static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ ShowStatus mode = _SHOW_STATUS_INVALID;
+ const char *t;
+ int r;
+
+ assert(m);
+ assert(message);
+
+ r = sd_bus_message_read(message, "s", &t);
+ if (r < 0)
+ return r;
+
+ if (!isempty(t)) {
+ mode = show_status_from_string(t);
+ if (mode < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid show status '%s'", t);
+ }
+
+ manager_override_show_status(m, mode, "bus");
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_VTABLE_START(0),
@@ -2786,6 +2808,12 @@ const sd_bus_vtable bus_manager_vtable[] = {
NULL,
method_reset_failed,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SetShowStatus",
+ "s",
+ SD_BUS_PARAM(mode),
+ NULL,,
+ method_set_show_status,
+ SD_BUS_VTABLE_CAPABILITY(CAP_SYS_ADMIN)),
SD_BUS_METHOD_WITH_NAMES("ListUnits",
NULL,,
"a(ssssssouso)",
diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c
index 4330c0f2c1..1565a79927 100644
--- a/src/core/emergency-action.c
+++ b/src/core/emergency-action.c
@@ -12,6 +12,18 @@
#include "terminal-util.h"
#include "virt.h"
+static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
+ [EMERGENCY_ACTION_NONE] = "none",
+ [EMERGENCY_ACTION_REBOOT] = "reboot",
+ [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
+ [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
+ [EMERGENCY_ACTION_POWEROFF] = "poweroff",
+ [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
+ [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
+ [EMERGENCY_ACTION_EXIT] = "exit",
+ [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
+};
+
static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
if (warn)
@@ -28,10 +40,22 @@ void emergency_action(
int exit_status,
const char *reason) {
+ Unit *u;
+
assert(m);
assert(action >= 0);
assert(action < _EMERGENCY_ACTION_MAX);
+ /* Is the special shutdown target active or queued? If so, we are in shutdown state */
+ if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
+ u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
+ if (u && unit_active_or_pending(u)) {
+ log_notice("Shutdown is already active. Skipping emergency action request %s.",
+ emergency_action_table[action]);
+ return;
+ }
+ }
+
if (action == EMERGENCY_ACTION_NONE)
return;
@@ -126,17 +150,6 @@ void emergency_action(
}
}
-static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
- [EMERGENCY_ACTION_NONE] = "none",
- [EMERGENCY_ACTION_REBOOT] = "reboot",
- [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
- [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
- [EMERGENCY_ACTION_POWEROFF] = "poweroff",
- [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
- [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
- [EMERGENCY_ACTION_EXIT] = "exit",
- [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
-};
DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
int parse_emergency_action(
diff --git a/src/core/execute.c b/src/core/execute.c
index aa253a5ddf..e0835f9b92 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -54,6 +54,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "glob-util.h"
+#include "hexdecoct.h"
#include "io-util.h"
#include "ioprio.h"
#include "label.h"
@@ -2666,6 +2667,7 @@ static int apply_mount_namespace(
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
+ context->root_hash, context->root_hash_size, context->root_hash_path, context->root_verity,
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
error_path);
@@ -4195,6 +4197,10 @@ void exec_context_done(ExecContext *c) {
c->working_directory = mfree(c->working_directory);
c->root_directory = mfree(c->root_directory);
c->root_image = mfree(c->root_image);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_verity = mfree(c->root_verity);
c->tty_path = mfree(c->tty_path);
c->syslog_identifier = mfree(c->syslog_identifier);
c->user = mfree(c->user);
@@ -4599,6 +4605,19 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
if (c->root_image)
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
+ if (c->root_hash) {
+ _cleanup_free_ char *encoded = NULL;
+ encoded = hexmem(c->root_hash, c->root_hash_size);
+ if (encoded)
+ fprintf(f, "%sRootHash: %s\n", prefix, encoded);
+ }
+
+ if (c->root_hash_path)
+ fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
+
+ if (c->root_verity)
+ fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
+
STRV_FOREACH(e, c->environment)
fprintf(f, "%sEnvironment: %s\n", prefix, *e);
diff --git a/src/core/execute.h b/src/core/execute.h
index 7e1015631f..7c9d63c5e4 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -155,7 +155,9 @@ struct ExecContext {
char **unset_environment;
struct rlimit *rlimit[_RLIMIT_MAX];
- char *working_directory, *root_directory, *root_image;
+ char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path;
+ void *root_hash;
+ size_t root_hash_size;
bool working_directory_missing_ok:1;
bool working_directory_home:1;
diff --git a/src/core/job.c b/src/core/job.c
index d518ac8969..ff49136d70 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -387,62 +387,25 @@ JobType job_type_lookup_merge(JobType a, JobType b) {
return job_merging_table[(a - 1) * a / 2 + b];
}
-bool job_later_link_matters(Job *j, JobType type, unsigned generation) {
- JobDependency *l;
-
- assert(j);
-
- j->generation = generation;
-
- LIST_FOREACH(subject, l, j->subject_list) {
- UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
-
- /* Have we seen this before? */
- if (l->object->generation == generation)
- continue;
-
- state = unit_active_state(l->object->unit);
- switch (type) {
-
- case JOB_START:
- return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) ||
- job_later_link_matters(l->object, type, generation);
-
- case JOB_STOP:
- return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) ||
- job_later_link_matters(l->object, type, generation);
-
- default:
- assert_not_reached("Invalid job type");
- }
- }
-
- return false;
-}
-
-bool job_is_redundant(Job *j, unsigned generation) {
-
- assert(j);
-
- UnitActiveState state = unit_active_state(j->unit);
- switch (j->type) {
+bool job_type_is_redundant(JobType a, UnitActiveState b) {
+ switch (a) {
case JOB_START:
- return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) && !job_later_link_matters(j, JOB_START, generation);
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_STOP:
- return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) && !job_later_link_matters(j, JOB_STOP, generation);
+ return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
case JOB_VERIFY_ACTIVE:
- return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING);
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_RELOAD:
return
- state == UNIT_RELOADING;
+ b == UNIT_RELOADING;
case JOB_RESTART:
return
- state == UNIT_ACTIVATING;
+ b == UNIT_ACTIVATING;
case JOB_NOP:
return true;
diff --git a/src/core/job.h b/src/core/job.h
index 02b057ee06..03ad640618 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -196,8 +196,7 @@ _pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
return a == job_type_lookup_merge(a, b);
}
-bool job_later_link_matters(Job *j, JobType type, unsigned generation);
-bool job_is_redundant(Job *j, unsigned generation);
+bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
/* Collapses a state-dependent job type into a simpler type by observing
* the state of the unit which it is going to be applied to. */
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 69598e8430..9cf959edd5 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -23,6 +23,8 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
+$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
+$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index c5664f968b..c3186f3824 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -29,6 +29,7 @@
#include "errno-list.h"
#include "escape.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "io-util.h"
@@ -1413,6 +1414,64 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
return 0;
}
+int config_parse_exec_root_hash(
+ 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_ void *roothash_decoded = NULL;
+ ExecContext *c = data;
+ size_t roothash_decoded_size = 0;
+ int r;
+
+ assert(data);
+ assert(filename);
+ assert(line);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ /* Reset if the empty string is assigned */
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ return 0;
+ }
+
+ if (path_is_absolute(rvalue)) {
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ _cleanup_free_ char *p = NULL;
+
+ p = strdup(rvalue);
+ if (!p)
+ return -ENOMEM;
+
+ free_and_replace(c->root_hash_path, p);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ return 0;
+ }
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(rvalue, strlen(rvalue), &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "RootHash= is too short, ignoring: %s", rvalue);
+
+ free_and_replace(c->root_hash, roothash_decoded);
+ c->root_hash_size = roothash_decoded_size;
+ c->root_hash_path = mfree(c->root_hash_path);
+
+ return 0;
+}
+
int config_parse_exec_cpu_affinity(const char *unit,
const char *filename,
unsigned line,
@@ -3393,8 +3452,6 @@ int config_parse_memory_limit(
}
}
- /* Keep Memory{Low,Min} unset with empty assignment so that we fall back to DefaultMemory* which in
- * contrast means zeroing the property. */
if (streq(lvalue, "DefaultMemoryLow")) {
c->default_memory_low = bytes;
c->default_memory_low_set = true;
@@ -3403,10 +3460,10 @@ int config_parse_memory_limit(
c->default_memory_min_set = true;
} else if (streq(lvalue, "MemoryMin")) {
c->memory_min = bytes;
- c->memory_min_set = !isempty(rvalue);
+ c->memory_min_set = true;
} else if (streq(lvalue, "MemoryLow")) {
c->memory_low = bytes;
- c->memory_low_set = !isempty(rvalue);
+ c->memory_low_set = true;
} else if (streq(lvalue, "MemoryHigh"))
c->memory_high = bytes;
else if (streq(lvalue, "MemoryMax"))
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 9c30b6f882..f0e109da3a 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -44,6 +44,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
diff --git a/src/core/main.c b/src/core/main.c
index 6e606d412a..a2ff71fa71 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -2559,7 +2559,7 @@ int main(int argc, char *argv[]) {
}
if (mac_selinux_init() < 0) {
- error_message = "Failed to initialize SELinux policy";
+ error_message = "Failed to initialize SELinux support";
goto finish;
}
@@ -2603,6 +2603,11 @@ int main(int argc, char *argv[]) {
/* clear the kernel timestamp,
* because we are not PID 1 */
kernel_timestamp = DUAL_TIMESTAMP_NULL;
+
+ if (mac_selinux_init() < 0) {
+ error_message = "Failed to initialize SELinux support";
+ goto finish;
+ }
}
if (arg_system) {
diff --git a/src/core/manager.c b/src/core/manager.c
index 48bd86e54f..ab3d0b1192 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -779,6 +779,8 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
.watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
.watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
+ .show_status_overridden = _SHOW_STATUS_INVALID,
+
.notify_fd = -1,
.cgroups_agent_fd = -1,
.signal_fd = -1,
@@ -2759,11 +2761,11 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
- manager_set_show_status(m, SHOW_STATUS_YES, "signal");
+ manager_override_show_status(m, SHOW_STATUS_YES, "signal");
break;
case 21:
- manager_set_show_status(m, SHOW_STATUS_NO, "signal");
+ manager_override_show_status(m, SHOW_STATUS_NO, "signal");
break;
case 22:
@@ -3219,9 +3221,9 @@ int manager_serialize(
/* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
(void) serialize_bool(f, "honor-device-enumeration", !switching_root);
- t = show_status_to_string(m->show_status);
- if (t)
- (void) serialize_item(f, "show-status", t);
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ (void) serialize_item(f, "show-status-overridden",
+ show_status_to_string(m->show_status_overridden));
if (m->log_level_overridden)
(void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
@@ -3399,7 +3401,7 @@ void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
m->watchdog[t] = timeout;
}
-int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) {
+int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
int r = 0;
assert(m);
@@ -3568,14 +3570,14 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
else
m->honor_device_enumeration = b;
- } else if ((val = startswith(l, "show-status="))) {
+ } else if ((val = startswith(l, "show-status-overridden="))) {
ShowStatus s;
s = show_status_from_string(val);
if (s < 0)
- log_notice("Failed to parse show-status flag '%s', ignoring.", val);
+ log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
else
- manager_set_show_status(m, s, "deserialization");
+ manager_override_show_status(m, s, "deserialize");
} else if ((val = startswith(l, "log-level-override="))) {
int level;
@@ -3601,7 +3603,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
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);
+ manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
} else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
usec_t t;
@@ -3609,7 +3611,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
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);
+ manager_override_watchdog(m, WATCHDOG_REBOOT, t);
} else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
usec_t t;
@@ -3617,7 +3619,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
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);
+ manager_override_watchdog(m, WATCHDOG_KEXEC, t);
} else if (startswith(l, "env=")) {
r = deserialize_environment(l + 4, &m->client_environment);
@@ -4264,49 +4266,78 @@ void manager_recheck_journal(Manager *m) {
log_open();
}
+static ShowStatus manager_get_show_status(Manager *m) {
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return _SHOW_STATUS_INVALID;
+
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ return m->show_status_overridden;
+
+ return m->show_status;
+}
+
+bool manager_get_show_status_on(Manager *m) {
+ assert(m);
+
+ return show_status_on(manager_get_show_status(m));
+}
+
+static void set_show_status_marker(bool b) {
+ if (b)
+ (void) touch("/run/systemd/show-status");
+ else
+ (void) unlink("/run/systemd/show-status");
+}
+
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
+ assert(reason);
assert(mode >= 0 && mode < _SHOW_STATUS_MAX);
- if (!MANAGER_IS_SYSTEM(m))
+ if (MANAGER_IS_USER(m))
return;
if (mode == m->show_status)
return;
- bool enabled = IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
- log_debug("%s (%s) showing of status (%s).",
- enabled ? "Enabling" : "Disabling",
- strna(show_status_to_string(mode)),
- reason);
- m->show_status = mode;
+ if (m->show_status_overridden == _SHOW_STATUS_INVALID) {
+ bool enabled;
- if (enabled)
- (void) touch("/run/systemd/show-status");
- else
- (void) unlink("/run/systemd/show-status");
+ enabled = show_status_on(mode);
+ log_debug("%s (%s) showing of status (%s).",
+ enabled ? "Enabling" : "Disabling",
+ strna(show_status_to_string(mode)),
+ reason);
+
+ set_show_status_marker(enabled);
+ }
+
+ m->show_status = mode;
}
-static bool manager_get_show_status(Manager *m, StatusType type) {
+void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
+ assert(mode < _SHOW_STATUS_MAX);
- if (!MANAGER_IS_SYSTEM(m))
- return false;
+ if (MANAGER_IS_USER(m))
+ return;
- if (m->no_console_output)
- return false;
+ if (mode == m->show_status_overridden)
+ return;
- if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
- return false;
+ m->show_status_overridden = mode;
- /* If we cannot find out the status properly, just proceed. */
- if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
- return false;
+ if (mode == _SHOW_STATUS_INVALID)
+ mode = m->show_status;
- if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
- return true;
+ log_debug("%s (%s) showing of status (%s).",
+ m->show_status_overridden != _SHOW_STATUS_INVALID ? "Overriding" : "Restoring",
+ strna(show_status_to_string(mode)),
+ reason);
- return show_status_on(m->show_status);
+ set_show_status_marker(show_status_on(mode));
}
const char *manager_get_confirm_spawn(Manager *m) {
@@ -4381,12 +4412,34 @@ bool manager_is_confirm_spawn_disabled(Manager *m) {
return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
}
+static bool manager_should_show_status(Manager *m, StatusType type) {
+ assert(m);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return false;
+
+ if (m->no_console_output)
+ return false;
+
+ if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
+ return false;
+
+ /* If we cannot find out the status properly, just proceed. */
+ if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
+ return false;
+
+ if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
+ return true;
+
+ return manager_get_show_status_on(m);
+}
+
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
va_list ap;
/* If m is NULL, assume we're after shutdown and let the messages through. */
- if (m && !manager_get_show_status(m, type))
+ if (m && !manager_should_show_status(m, type))
return;
/* XXX We should totally drop the check for ephemeral here
diff --git a/src/core/manager.h b/src/core/manager.h
index a29d976eae..2cd0dacdb0 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -335,6 +335,7 @@ struct Manager {
uint8_t return_value;
ShowStatus show_status;
+ ShowStatus show_status_overridden;
StatusUnitFormat status_unit_format;
char *confirm_spawn;
bool no_console_output;
@@ -512,7 +513,10 @@ void disable_printk_ratelimit(void);
void manager_recheck_dbus(Manager *m);
void manager_recheck_journal(Manager *m);
+bool manager_get_show_status_on(Manager *m);
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason);
+void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason);
+
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);
@@ -553,7 +557,7 @@ 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);
+int manager_override_watchdog(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_;
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 6bfc266dc0..423a47c7b8 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -1257,16 +1257,20 @@ int setup_namespace(
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+ const void *root_hash,
+ size_t root_hash_size,
+ const char *root_hash_path,
+ const char *root_verity,
DissectImageFlags dissect_image_flags,
char **error_path) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_free_ void *root_hash = NULL;
+ _cleanup_free_ void *root_hash_decoded = NULL;
_cleanup_free_ char *verity_data = NULL;
MountEntry *m = NULL, *mounts = NULL;
- size_t n_mounts, root_hash_size = 0;
+ size_t n_mounts;
bool require_prefix = false;
const char *root;
int r = 0;
@@ -1295,16 +1299,16 @@ int setup_namespace(
if (r < 0)
return log_debug_errno(r, "Failed to create loop device for root image: %m");
- r = verity_metadata_load(root_image, &root_hash, &root_hash_size, &verity_data);
+ r = verity_metadata_load(root_image, root_hash_path, root_hash ? NULL : &root_hash_decoded, root_hash ? NULL : &root_hash_size, root_verity ? NULL : &verity_data);
if (r < 0)
return log_debug_errno(r, "Failed to load root hash: %m");
- dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
+ dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
- r = dissect_image(loop_device->fd, root_hash, root_hash_size, verity_data, dissect_image_flags, &dissected_image);
+ r = dissect_image(loop_device->fd, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &dissected_image);
if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m");
- r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, verity_data, dissect_image_flags, &decrypted_image);
+ r = dissected_image_decrypt(dissected_image, NULL, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &decrypted_image);
if (r < 0)
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
}
diff --git a/src/core/namespace.h b/src/core/namespace.h
index ef6c9bdc9b..a687be5bfd 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -88,6 +88,10 @@ int setup_namespace(
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+ const void *root_hash,
+ size_t root_hash_size,
+ const char *root_hash_path,
+ const char *root_verity,
DissectImageFlags dissected_image_flags,
char **error_path);
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 415b3f5d84..9a5912c10f 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -318,6 +318,10 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="AddDependencyUnitFiles"/>
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
+ send_member="SetShowStatus"/>
+
<!-- Managed via polkit or other criteria: org.freedesktop.systemd1.Job interface -->
<allow send_destination="org.freedesktop.systemd1"
diff --git a/src/core/transaction.c b/src/core/transaction.c
index 0fb52372f1..ef6470656c 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -279,7 +279,7 @@ static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
return 0;
}
-static void transaction_drop_redundant(Transaction *tr, unsigned generation) {
+static void transaction_drop_redundant(Transaction *tr) {
bool again;
/* Goes through the transaction and removes all jobs of the units whose jobs are all noops. If not
@@ -299,7 +299,7 @@ static void transaction_drop_redundant(Transaction *tr, unsigned generation) {
LIST_FOREACH(transaction, k, j)
if (tr->anchor_job == k ||
- !job_is_redundant(k, generation) ||
+ !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
(k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) {
keep = true;
break;
@@ -735,7 +735,7 @@ int transaction_activate(
transaction_minimize_impact(tr);
/* Third step: Drop redundant jobs */
- transaction_drop_redundant(tr, generation++);
+ transaction_drop_redundant(tr);
for (;;) {
/* Fourth step: Let's remove unneeded jobs that might
@@ -777,7 +777,7 @@ int transaction_activate(
}
/* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
- transaction_drop_redundant(tr, generation++);
+ transaction_drop_redundant(tr);
/* Ninth step: check whether we can actually apply this */
r = transaction_is_destructive(tr, mode, e);
diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c
index ed4d06e986..eceb7927af 100644
--- a/src/coredump/coredumpctl.c
+++ b/src/coredump/coredumpctl.c
@@ -1091,9 +1091,7 @@ static int run(int argc, char *argv[]) {
int r, units_active;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
diff --git a/src/delta/delta.c b/src/delta/delta.c
index 2d80d3a664..29e5120375 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -643,9 +643,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
int r, k, n_found = 0;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index 7fb80ca138..4f38de8e29 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -128,9 +128,7 @@ static int run(int argc, char *argv[]) {
* to detect whether we are being run in a virtualized
* environment or not */
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index 9ae632f226..2a8eaca5bd 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -201,7 +201,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device: %m");
- r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
+ r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0)
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
diff --git a/src/escape/escape.c b/src/escape/escape.c
index 9066c30853..0c543a90f6 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -159,9 +159,7 @@ static int run(int argc, char *argv[]) {
char **i;
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/home/homectl.c b/src/home/homectl.c
index f7237d22d8..7a473b791b 100644
--- a/src/home/homectl.c
+++ b/src/home/homectl.c
@@ -3489,9 +3489,7 @@ static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index 5596846ed2..e08ab15acd 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -436,9 +436,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index e694a95a04..36229f3c9b 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -801,7 +801,10 @@ static int run(int argc, char *argv[]) {
return r;
umask(0022);
- mac_selinux_init();
+
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 651647b3f0..eb038a8b55 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -125,7 +125,9 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
return hwdb_main(argc, argv);
}
diff --git a/src/id128/id128.c b/src/id128/id128.c
index 19435f80fe..13996573ab 100644
--- a/src/id128/id128.c
+++ b/src/id128/id128.c
@@ -249,9 +249,7 @@ static int id128_main(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c
index 948b2d2fce..69a111afea 100644
--- a/src/journal-remote/journal-remote-main.c
+++ b/src/journal-remote/journal-remote-main.c
@@ -1110,7 +1110,7 @@ static int run(int argc, char **argv) {
int r;
log_show_color(true);
- log_parse_environment();
+ log_parse_environment_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index bd58fdbcdf..e169a27eb3 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -821,7 +821,7 @@ static int run(int argc, char **argv) {
int r;
log_show_color(true);
- log_parse_environment();
+ log_parse_environment_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
diff --git a/src/journal/cat.c b/src/journal/cat.c
index 500b674505..2faaa2e284 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -129,9 +129,7 @@ static int run(int argc, char *argv[]) {
_cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1;
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 36bd9a0148..8d4897b942 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2110,9 +2110,7 @@ int main(int argc, char *argv[]) {
int n_shown = 0, r, poll_fd = -1;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
* split up into many files. */
diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h
index aed30d6118..66222eaddb 100644
--- a/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libsystemd-network/dhcp-lease-internal.h
@@ -82,6 +82,3 @@ int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const vo
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len);
-
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
-int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index aa61bc2614..e4c11235b6 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -61,9 +61,13 @@ int deserialize_in6_addrs(struct in6_addr **addresses, const char *string);
/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */
struct sd_dhcp_route;
+struct sd_dhcp_lease;
void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size);
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string);
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
+
+int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
+int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 8582302cb4..0bc5fa3210 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -1076,7 +1076,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
"ADDRESS", &address,
"ROUTER", &router,
"NETMASK", &netmask,
- "SERVER_IDENTIFIER", &server_address,
+ "SERVER_ADDRESS", &server_address,
"NEXT_SERVER", &next_server,
"BROADCAST", &broadcast,
"DNS", &dns,
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 97b732ae42..55e35cd902 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -451,7 +451,7 @@ int bus_message_from_header(
if (!IN_SET(h->version, 1, 2))
return -EBADMSG;
- if (h->type <= _SD_BUS_MESSAGE_TYPE_INVALID || h->type >= _SD_BUS_MESSAGE_TYPE_MAX)
+ if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
return -EBADMSG;
if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
@@ -589,7 +589,8 @@ _public_ int sd_bus_message_new(
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_INVALID && type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
+ /* Creation of messages with _SD_BUS_MESSAGE_TYPE_INVALID is allowed. */
+ assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
if (!t)
@@ -3021,7 +3022,7 @@ int bus_body_part_map(struct bus_body_part *part) {
return 0;
}
- shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
+ shift = PAGE_OFFSET(part->memfd_offset);
psz = PAGE_ALIGN(part->size + shift);
if (part->memfd >= 0)
@@ -3158,7 +3159,8 @@ static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t s
return NULL;
if (p)
- *p = (uint8_t*) part->data + index - begin;
+ *p = part->data ? (uint8_t*) part->data + index - begin
+ : NULL; /* Avoid dereferencing a NULL pointer. */
m->cached_rindex_part = part;
m->cached_rindex_part_begin = begin;
@@ -5497,9 +5499,6 @@ int bus_message_parse_fields(sd_bus_message *m) {
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 */
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index 30f47244ad..ce6ae846c5 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -168,10 +168,6 @@ _public_ int sd_network_link_get_address_state(int ifindex, char **state) {
return network_link_get_string(ifindex, "ADDRESS_STATE", state);
}
-_public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id) {
- return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id);
-}
-
_public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) {
return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid);
}
@@ -236,14 +232,6 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char
return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
}
-_public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
- return network_link_get_string(ifindex, "TIMEZONE", ret);
-}
-
-_public_ int sd_network_link_get_dhcp4_address(int ifindex, char **ret) {
- return network_link_get_string(ifindex, "DHCP4_ADDRESS", ret);
-}
-
_public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "DNS", ret);
}
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index b7548a0f7f..96fc09a570 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -502,9 +502,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/locale/localed.c b/src/locale/localed.c
index 8ffcf306b5..715ce5cac7 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -18,6 +18,7 @@
#include "bus-message.h"
#include "bus-polkit.h"
#include "def.h"
+#include "dlfcn-util.h"
#include "keymap-util.h"
#include "locale-util.h"
#include "macro.h"
@@ -530,7 +531,7 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
};
struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL;
- void *dl;
+ _cleanup_(dlclosep) void *dl = NULL;
int r;
/* Compile keymap from RMLVO information to check out its validity */
@@ -582,7 +583,6 @@ finish:
if (symbol_xkb_context_unref && ctx)
symbol_xkb_context_unref(ctx);
- (void) dlclose(dl);
return r;
}
@@ -788,7 +788,10 @@ static int run(int argc, char *argv[]) {
return r;
umask(0022);
- mac_selinux_init();
+
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
diff --git a/src/locale/meson.build b/src/locale/meson.build
index e87a10ebeb..314b0a3d37 100644
--- a/src/locale/meson.build
+++ b/src/locale/meson.build
@@ -34,5 +34,5 @@ tests += [
'src/locale/keymap-util.c',
'src/locale/keymap-util.h'],
[libshared],
- [libdl]],
+ []],
]
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 7805863d8d..9216224bfc 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -1460,9 +1460,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
diff --git a/src/login/logind.c b/src/login/logind.c
index dc746a2c9e..377fba25cf 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1173,7 +1173,7 @@ static int run(int argc, char *argv[]) {
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "Could not initialize labelling: %m");
+ return r;
/* Always create the directories people can create inotify watches in. Note that some applications might check
* for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make
diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c
index fdf0124c41..38058d7b2a 100644
--- a/src/login/user-runtime-dir.c
+++ b/src/login/user-runtime-dir.c
@@ -192,11 +192,11 @@ static int run(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"First argument must be either \"start\" or \"stop\".");
+ umask(0022);
+
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "Could not initialize labelling: %m\n");
-
- umask(0022);
+ return r;
if (streq(argv[1], "start"))
return do_mount(argv[2]);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index d88b2651d2..d8f4526644 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -2882,9 +2882,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index bf663146d6..8b7cf292fa 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <arpa/inet.h>
#include <getopt.h>
#include <linux/if_addrlabel.h>
#include <net/if.h>
@@ -930,12 +931,13 @@ static int dump_gateways(
static int dump_addresses(
sd_netlink *rtnl,
+ sd_dhcp_lease *lease,
Table *table,
int ifindex) {
_cleanup_free_ struct local_address *local = NULL;
- _cleanup_free_ char *dhcp4_address = NULL;
_cleanup_strv_free_ char **buf = NULL;
+ struct in_addr dhcp4_address = {};
int r, n, i;
assert(rtnl);
@@ -945,7 +947,8 @@ static int dump_addresses(
if (n <= 0)
return n;
- (void) sd_network_link_get_dhcp4_address(ifindex, &dhcp4_address);
+ if (lease)
+ (void) sd_dhcp_lease_get_address(lease, &dhcp4_address);
for (i = 0; i < n; i++) {
_cleanup_free_ char *pretty = NULL;
@@ -955,13 +958,19 @@ static int dump_addresses(
if (r < 0)
return r;
- if (dhcp4_address && streq(pretty, dhcp4_address)) {
- _cleanup_free_ char *p = NULL;
+ if (local[i].family == AF_INET && in4_addr_equal(&local[i].address.in, &dhcp4_address)) {
+ struct in_addr server_address;
+ char *p, s[INET_ADDRSTRLEN];
- p = pretty;
- pretty = strjoin(pretty , " (DHCP4)");
- if (!pretty)
+ r = sd_dhcp_lease_get_server_identifier(lease, &server_address);
+ if (r >= 0 && inet_ntop(AF_INET, &server_address, s, sizeof(s)))
+ p = strjoin(pretty, " (DHCP4 via ", s, ")");
+ else
+ p = strjoin(pretty, " (DHCP4)");
+ if (!p)
return log_oom();
+
+ free_and_replace(pretty, p);
}
r = strv_extendf(&buf, "%s%s%s",
@@ -1379,12 +1388,12 @@ static int link_status_one(
const LinkInfo *info) {
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL;
- _cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL, *iaid = NULL, *duid = NULL;
- const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
- _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- const char *on_color_operational, *off_color_operational,
- *on_color_setup, *off_color_setup;
+ _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
+ *setup_state = NULL, *operational_state = NULL, *lease_file = NULL;
+ const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
+ *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup;
_cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
+ _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
TableCell *cell;
int r;
@@ -1425,6 +1434,11 @@ static int link_status_one(
(void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
(void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
+ if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", info->ifindex) < 0)
+ return log_oom();
+
+ (void) dhcp_lease_load(&lease, lease_file);
+
table = table_new("dot", "key", "value");
if (!table)
return log_oom();
@@ -2022,7 +2036,7 @@ static int link_status_one(
}
}
- r = dump_addresses(rtnl, table, info->ifindex);
+ r = dump_addresses(rtnl, lease, table, info->ifindex);
if (r < 0)
return r;
r = dump_gateways(rtnl, hwdb, table, info->ifindex);
@@ -2050,24 +2064,35 @@ static int link_status_one(
if (r < 0)
return r;
- (void) sd_network_link_get_timezone(info->ifindex, &tz);
- if (tz) {
- r = table_add_many(table,
- TABLE_EMPTY,
- TABLE_STRING, "Time Zone:",
- TABLE_STRING, tz);
- if (r < 0)
- return table_log_add_error(r);
- }
+ if (lease) {
+ const void *client_id;
+ size_t client_id_len;
+ const char *tz;
- r = sd_network_link_get_dhcp4_client_id_string(info->ifindex, &client_id);
- if (r >= 0) {
- r = table_add_many(table,
- TABLE_EMPTY,
- TABLE_STRING, "DHCP4 Client ID:",
- TABLE_STRING, client_id);
- if (r < 0)
- return table_log_add_error(r);
+ r = sd_dhcp_lease_get_timezone(lease, &tz);
+ if (r >= 0) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "Time Zone:",
+ TABLE_STRING, tz);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
+ if (r >= 0) {
+ _cleanup_free_ char *id = NULL;
+
+ r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
+ if (r >= 0) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "DHCP4 Client ID:",
+ TABLE_STRING, id);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+ }
}
r = sd_network_link_get_dhcp6_client_iaid_string(info->ifindex, &iaid);
@@ -2147,7 +2172,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
if (r < 0)
return table_log_add_error(r);
- r = dump_addresses(rtnl, table, 0);
+ r = dump_addresses(rtnl, NULL, table, 0);
if (r < 0)
return r;
r = dump_gateways(rtnl, hwdb, table, 0);
@@ -2793,9 +2818,7 @@ static void warn_networkd_missing(void) {
static int run(int argc, char* argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c
index b3ed4a8cea..6f25c9fc96 100644
--- a/src/network/networkd-dhcp-server.c
+++ b/src/network/networkd-dhcp-server.c
@@ -116,7 +116,7 @@ static int link_push_uplink_to_dhcp_server(
case SD_DHCP_LEASE_LPR:
/* For the other server types we currently do not allow local configuration of server data,
* since there are typically no local consumers of the data. */
- ;
+ break;
default:
assert_not_reached("Unexpected server type");
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index f0766f0af7..27b74407af 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -1065,7 +1065,7 @@ static int dhcp6_assign_delegated_prefix(Link *link,
address->in_addr.in6 = *prefix;
if (!in_addr_is_null(AF_INET6, &link->network->dhcp6_delegation_prefix_token))
- memcpy(&address->in_addr.in6.s6_addr + 8, &link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8);
+ memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8);
else {
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index c2fb21c736..06a467d15b 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -4347,33 +4347,6 @@ int link_save(Link *link) {
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
if (link->dhcp_lease) {
- struct in_addr address;
- const char *tz = NULL;
- size_t client_id_len;
- const void *client_id;
-
- assert(link->network);
-
- r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
- if (r >= 0)
- fprintf(f, "TIMEZONE=%s\n", tz);
-
- r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
- if (r >= 0) {
- fputs("DHCP4_ADDRESS=", f);
- serialize_in_addrs(f, &address, 1, NULL, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_client_id(link->dhcp_lease, &client_id, &client_id_len);
- if (r >= 0) {
- _cleanup_free_ char *id = NULL;
-
- r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
- if (r >= 0)
- fprintf(f, "DHCP4_CLIENT_ID=%s\n", id);
- }
-
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
goto fail;
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index eb80c2960b..2fbaf65692 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -619,9 +619,9 @@ int mount_all(const char *dest,
#if HAVE_SELINUX
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
- 0 }, /* Bind mount first */
+ MOUNT_MKDIR }, /* Bind mount first (mkdir/chown the mount point in case /sys/ is mounted as minimal skeleton tmpfs) */
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
- 0 }, /* Then, make it r/o */
+ 0 }, /* Then, make it r/o (don't mkdir/chown the mount point here, the previous entry already did that) */
#endif
};
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index f3a3ee8a17..ae6828f2bf 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -5141,7 +5141,7 @@ static int run(int argc, char *argv[]) {
goto finish;
}
- r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
+ r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0) {
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index 6a2d9c885e..5dc5aacdff 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -8,6 +8,7 @@
#include "fd-util.h"
#include "group-record-nss.h"
#include "macro.h"
+#include "nss-systemd.h"
#include "nss-util.h"
#include "pthread-util.h"
#include "signal-util.h"
@@ -299,7 +300,7 @@ enum nss_status _nss_systemd_setpwent(int stayopen) {
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
- if (userdb_nss_compat_is_enabled() <= 0)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@@ -323,7 +324,7 @@ enum nss_status _nss_systemd_setgrent(int stayopen) {
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
- if (userdb_nss_compat_is_enabled() <= 0)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@@ -353,13 +354,7 @@ enum nss_status _nss_systemd_getpwent_r(
assert(result);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- UNPROTECT_ERRNO;
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@@ -406,14 +401,8 @@ enum nss_status _nss_systemd_getgrent_r(
assert(result);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- UNPROTECT_ERRNO;
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
- return NSS_STATUS_UNAVAIL;
+ if (_nss_systemd_is_blocked())
+ return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@@ -459,7 +448,7 @@ enum nss_status _nss_systemd_getgrent_r(
}
if (getgrent_data.by_membership) {
- _cleanup_close_ int lock_fd = -1;
+ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
for (;;) {
_cleanup_free_ char *user_name = NULL, *group_name = NULL;
@@ -479,13 +468,15 @@ enum nss_status _nss_systemd_getgrent_r(
continue;
/* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */
- if (lock_fd < 0) {
- lock_fd = userdb_nss_compat_disable();
- if (lock_fd < 0 && lock_fd != -EBUSY) {
+ if (!blocked) {
+ r = _nss_systemd_block(true);
+ if (r < 0) {
UNPROTECT_ERRNO;
- *errnop = -lock_fd;
+ *errnop = -r;
return NSS_STATUS_UNAVAIL;
}
+
+ blocked = true;
}
r = nss_group_record_by_name(group_name, false, &gr);
@@ -549,13 +540,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name))
return NSS_STATUS_NOTFOUND;
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- UNPROTECT_ERRNO;
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator);
@@ -581,7 +566,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
/* The group might be defined via traditional NSS only, hence let's do a full look-up without
* disabling NSS. This means we are operating recursively here. */
- r = groupdb_by_name(group_name, nss_glue_userdb_flags() & ~USERDB_AVOID_NSS, &g);
+ r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_AVOID_NSS) | USERDB_AVOID_SHADOW, &g);
if (r == -ESRCH)
continue;
if (r < 0) {
@@ -627,3 +612,29 @@ enum nss_status _nss_systemd_initgroups_dyn(
return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND;
}
+
+static thread_local unsigned _blocked = 0;
+
+_public_ int _nss_systemd_block(bool b) {
+
+ /* This blocks recursively: it's blocked for as many times this function is called with `true` until
+ * it is called an equal time with `false`. */
+
+ if (b) {
+ if (_blocked >= UINT_MAX)
+ return -EOVERFLOW;
+
+ _blocked++;
+ } else {
+ if (_blocked <= 0)
+ return -EOVERFLOW;
+
+ _blocked--;
+ }
+
+ return b; /* Return what is passed in, i.e. the new state from the PoV of the caller */
+}
+
+_public_ bool _nss_systemd_is_blocked(void) {
+ return _blocked > 0;
+}
diff --git a/src/nss-systemd/nss-systemd.h b/src/nss-systemd/nss-systemd.h
new file mode 100644
index 0000000000..ffa75c12c4
--- /dev/null
+++ b/src/nss-systemd/nss-systemd.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+int _nss_systemd_block(bool b);
+bool _nss_systemd_is_blocked(void);
+
+/* For use with the _cleanup_() macro */
+static inline void _nss_systemd_unblockp(bool *b) {
+ if (*b)
+ assert_se(_nss_systemd_block(false) >= 0);
+}
diff --git a/src/nss-systemd/nss-systemd.sym b/src/nss-systemd/nss-systemd.sym
index 77e1fbe93f..f86d7643d1 100644
--- a/src/nss-systemd/nss-systemd.sym
+++ b/src/nss-systemd/nss-systemd.sym
@@ -20,5 +20,9 @@ global:
_nss_systemd_setgrent;
_nss_systemd_getgrent_r;
_nss_systemd_initgroups_dyn;
+
+ /* These two are not used by glibc, but can be used by apps to explicitly disable nss-systemd for the calling thread. */
+ _nss_systemd_block;
+ _nss_systemd_is_blocked;
local: *;
};
diff --git a/src/nss-systemd/userdb-glue.c b/src/nss-systemd/userdb-glue.c
index da1248a132..8e5b3eba6c 100644
--- a/src/nss-systemd/userdb-glue.c
+++ b/src/nss-systemd/userdb-glue.c
@@ -3,6 +3,7 @@
#include "env-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
+#include "nss-systemd.h"
#include "strv.h"
#include "user-record.h"
#include "userdb-glue.h"
@@ -74,12 +75,7 @@ enum nss_status userdb_getpwnam(
assert(pwd);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = userdb_by_name(name, nss_glue_userdb_flags(), &hr);
@@ -112,12 +108,7 @@ enum nss_status userdb_getpwuid(
assert(pwd);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr);
@@ -214,12 +205,7 @@ enum nss_status userdb_getgrnam(
assert(gr);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = groupdb_by_name(name, nss_glue_userdb_flags(), &g);
@@ -235,7 +221,7 @@ enum nss_status userdb_getgrnam(
}
if (!g) {
- _cleanup_close_ int lock_fd = -1;
+ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
if (strv_isempty(members))
return NSS_STATUS_NOTFOUND;
@@ -245,11 +231,13 @@ enum nss_status userdb_getgrnam(
* acquire it, so that we can extend it (that's because glibc's group merging feature will
* merge groups only if both GID and name match and thus we need to have both first). It
* sucks behaving recursively likely this, but it's apparently what everybody does. We break
- * the recursion for ourselves via the userdb_nss_compat_disable() lock. */
+ * the recursion for ourselves via the _nss_systemd_block_nss() lock. */
+
+ r = _nss_systemd_block(true);
+ if (r < 0)
+ return r;
- lock_fd = userdb_nss_compat_disable();
- if (lock_fd < 0 && lock_fd != -EBUSY)
- return lock_fd;
+ blocked = true;
r = nss_group_record_by_name(name, false, &g);
if (r == -ESRCH)
@@ -285,12 +273,7 @@ enum nss_status userdb_getgrgid(
assert(gr);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g);
@@ -300,20 +283,21 @@ enum nss_status userdb_getgrgid(
}
if (!g) {
- _cleanup_close_ int lock_fd = -1;
+ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
/* So, quite possibly we have to extend an existing group record with additional members. But
* to do this we need to know the group name first. The group didn't exist via non-NSS
* queries though, hence let's try to acquire it here recursively via NSS. */
- lock_fd = userdb_nss_compat_disable();
- if (lock_fd < 0 && lock_fd != -EBUSY)
- return lock_fd;
+ r = _nss_systemd_block(true);
+ if (r < 0)
+ return r;
+
+ blocked = true;
r = nss_group_record_by_gid(gid, false, &g);
if (r == -ESRCH)
return NSS_STATUS_NOTFOUND;
-
if (r < 0) {
*errnop = -r;
return NSS_STATUS_UNAVAIL;
diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c
index 1bde30e90f..01614b6684 100644
--- a/src/portable/portablectl.c
+++ b/src/portable/portablectl.c
@@ -1119,9 +1119,7 @@ static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
index 3cadac7639..a80b450bc0 100644
--- a/src/resolve/resolvectl.c
+++ b/src/resolve/resolvectl.c
@@ -3174,9 +3174,7 @@ static int run(int argc, char **argv) {
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
if (streq(program_invocation_short_name, "resolvconf"))
r = resolvconf_parse_argv(argc, argv);
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index cf332b8cd5..906158c5ce 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -500,7 +500,7 @@ static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
}
static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
- DnsQueryCandidate *c;
+ _cleanup_(dns_query_candidate_freep) DnsQueryCandidate *c = NULL;
int r;
assert(q);
@@ -511,24 +511,21 @@ static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
return r;
/* If this a single-label domain on DNS, we might append a suitable search domain first. */
- if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0 &&
- dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna))) {
- /* OK, we need a search domain now. Let's find one for this scope */
+ if (!FLAGS_SET(q->flags, SD_RESOLVED_NO_SEARCH) &&
+ dns_scope_name_wants_search_domain(s, dns_question_first_name(q->question_idna))) {
+ /* OK, we want a search domain now. Let's find one for this scope */
r = dns_query_candidate_next_search_domain(c);
- if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
- goto fail;
+ if (r < 0)
+ return r;
}
r = dns_query_candidate_setup_transactions(c);
if (r < 0)
- goto fail;
+ return r;
+ TAKE_PTR(c);
return 0;
-
-fail:
- dns_query_candidate_free(c);
- return r;
}
static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h
index fc7ccf553e..fe8a219557 100644
--- a/src/resolve/resolved-dns-query.h
+++ b/src/resolve/resolved-dns-query.h
@@ -102,6 +102,8 @@ enum {
};
DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_free);
+
void dns_query_candidate_notify(DnsQueryCandidate *c);
int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, int family, uint64_t flags);
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 140cd25586..764ccee0e0 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -619,7 +619,7 @@ DnsScopeMatch dns_scope_good_domain(
manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
* for single-label names, i.e. one label. This is
- * particular relevant as it means a "." route on some
+ * particularly relevant as it means a "." route on some
* other scope won't pull all traffic away from
* us. (If people actually want to pull traffic away
* from us they should turn off LLMNR on the
@@ -651,20 +651,21 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
if (s->protocol == DNS_PROTOCOL_DNS) {
- /* On classic DNS, looking up non-address RRs is always
- * fine. (Specifically, we want to permit looking up
- * DNSKEY and DS records on the root and top-level
- * domains.) */
+ /* On classic DNS, looking up non-address RRs is always fine. (Specifically, we want to
+ * permit looking up DNSKEY and DS records on the root and top-level domains.) */
if (!dns_resource_key_is_address(key))
return true;
- /* However, we refuse to look up A and AAAA RRs on the
- * root and single-label domains, under the assumption
- * that those should be resolved via LLMNR or search
- * path only, and should not be leaked onto the
- * internet. */
- return !(dns_name_is_single_label(dns_resource_key_name(key)) ||
- dns_name_is_root(dns_resource_key_name(key)));
+ /* Unless explicitly overridden, we refuse to look up A and AAAA RRs on the root and
+ * single-label domains, under the assumption that those should be resolved via LLMNR or
+ * search path only, and should not be leaked onto the internet. */
+ const char* name = dns_resource_key_name(key);
+
+ if (!s->manager->resolve_unicast_single_label &&
+ dns_name_is_single_label(name))
+ return false;
+
+ return !dns_name_is_root(name);
}
/* On mDNS and LLMNR, send A and AAAA queries only on the
@@ -1169,7 +1170,7 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
return s->manager->search_domains;
}
-bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
+bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name) {
assert(s);
if (s->protocol != DNS_PROTOCOL_DNS)
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 974692be5b..b356b92120 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -99,7 +99,7 @@ void dns_scope_dump(DnsScope *s, FILE *f);
DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s);
-bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
+bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name);
bool dns_scope_network_good(DnsScope *s);
diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf
index 4a451ccc4c..553da8d251 100644
--- a/src/resolve/resolved-gperf.gperf
+++ b/src/resolve/resolved-gperf.gperf
@@ -18,13 +18,14 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
-Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
-Resolve.Domains, config_parse_search_domains, 0, 0
-Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
-Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
-Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
-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)
+Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
+Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
+Resolve.Domains, config_parse_search_domains, 0, 0
+Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
+Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
+Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
+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)
+Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 6fa5e734bb..59944df746 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -70,9 +70,10 @@ struct Manager {
LIST_HEAD(DnsSearchDomain, search_domains);
unsigned n_search_domains;
- bool need_builtin_fallbacks:1;
+ bool need_builtin_fallbacks;
+ bool read_resolv_conf;
+ bool resolve_unicast_single_label;
- bool read_resolv_conf:1;
struct stat resolv_conf_stat;
DnsTrustAnchor trust_anchor;
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 50989a6b0a..566b950a63 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -40,7 +40,7 @@ static int run(int argc, char *argv[]) {
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "SELinux setup failed: %m");
+ return r;
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
* privileges are already dropped and we can't create our directory. */
diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
index 85822e316c..082ad71626 100644
--- a/src/resolve/resolved.conf.in
+++ b/src/resolve/resolved.conf.in
@@ -22,3 +22,4 @@
#Cache=yes
#DNSStubListener=yes
#ReadEtcHosts=yes
+#ResolveUnicastSingleLabel=no
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 4b1145a6ba..d93d5d6013 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -13,6 +13,7 @@
#include "escape.h"
#include "exec-util.h"
#include "exit-status.h"
+#include "fileio.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
@@ -24,6 +25,7 @@
#include "nsflags.h"
#include "numa-util.h"
#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "securebits-util.h"
@@ -494,18 +496,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
if (r < 0)
return bus_log_create_error(r);
return 1;
- } else if (isempty(eq) && STR_IN_SET(field, "DefaultMemoryLow",
- "DefaultMemoryMin",
- "MemoryLow",
- "MemoryMin")) {
- /* We can't use CGROUP_LIMIT_MIN nor CGROUP_LIMIT_MAX to convey the empty assignment
- * so marshall specially as a boolean. */
- r = sd_bus_message_append(m, "(sv)", field, "b", 0);
- if (r < 0)
- return bus_log_create_error(r);
- return 1;
} else if (isempty(eq)) {
- r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
+ uint64_t empty_value = STR_IN_SET(field,
+ "DefaultMemoryLow",
+ "DefaultMemoryMin",
+ "MemoryLow",
+ "MemoryMin") ?
+ CGROUP_LIMIT_MIN :
+ CGROUP_LIMIT_MAX;
+
+ r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
if (r < 0)
return bus_log_create_error(r);
return 1;
@@ -849,6 +849,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"ProtectHome",
"SELinuxContext",
"RootImage",
+ "RootVerity",
"RuntimeDirectoryPreserve",
"Personality",
"KeyringMode",
@@ -1415,6 +1416,24 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
return 1;
}
+ if (streq(field, "RootHash")) {
+ _cleanup_free_ void *roothash_decoded = NULL;
+ size_t roothash_decoded_size = 0;
+
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ if (path_is_absolute(eq))
+ return bus_append_string(m, "RootHashPath", eq);
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
+
+ return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
+ }
+
return 0;
}
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 2c8a5d85bf..e576518c6b 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -1421,7 +1421,7 @@ int decrypted_image_relinquish(DecryptedImage *d) {
return 0;
}
-int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
+int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
_cleanup_free_ char *verity_filename = NULL;
_cleanup_free_ void *roothash_decoded = NULL;
size_t roothash_decoded_size = 0;
@@ -1465,24 +1465,31 @@ int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roo
_cleanup_free_ char *text = NULL;
assert(ret_roothash_size);
- r = getxattr_malloc(image, "user.verity.roothash", &text, true);
- if (r < 0) {
- char *fn, *e, *n;
-
- if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
+ if (root_hash_path) {
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ r = read_one_line_file(root_hash_path, &text);
+ if (r < 0)
return r;
+ } else {
+ r = getxattr_malloc(image, "user.verity.roothash", &text, true);
+ if (r < 0) {
+ char *fn, *e, *n;
+
+ if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
+ return r;
- fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
- n = stpcpy(fn, image);
- e = endswith(fn, ".raw");
- if (e)
- n = e;
+ fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
+ n = stpcpy(fn, image);
+ e = endswith(fn, ".raw");
+ if (e)
+ n = e;
- strcpy(n, ".roothash");
+ strcpy(n, ".roothash");
- r = read_one_line_file(fn, &text);
- if (r < 0 && r != -ENOENT)
- return r;
+ r = read_one_line_file(fn, &text);
+ if (r < 0 && r != -ENOENT)
+ return r;
+ }
}
if (text) {
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index 92d223cfec..6a53b94948 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -100,6 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d);
const char* partition_designator_to_string(int i) _const_;
int partition_designator_from_string(const char *name) _pure_;
-int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
+int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
diff --git a/src/shared/userdb.c b/src/shared/userdb.c
index cd9873c06e..6fedbd6ebe 100644
--- a/src/shared/userdb.c
+++ b/src/shared/userdb.c
@@ -3,6 +3,7 @@
#include <sys/auxv.h>
#include "dirent-util.h"
+#include "dlfcn-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
@@ -32,8 +33,8 @@ struct UserDBIterator {
bool nss_iterating:1;
bool synthesize_root:1;
bool synthesize_nobody:1;
+ bool nss_systemd_blocked:1;
int error;
- int nss_lock;
unsigned n_found;
sd_event *event;
UserRecord *found_user; /* when .what == LOOKUP_USER */
@@ -85,7 +86,9 @@ UserDBIterator* userdb_iterator_free(UserDBIterator *iterator) {
}
sd_event_unref(iterator->event);
- safe_close(iterator->nss_lock);
+
+ if (iterator->nss_systemd_blocked)
+ assert_se(userdb_block_nss_systemd(false) >= 0);
return mfree(iterator);
}
@@ -102,12 +105,27 @@ static UserDBIterator* userdb_iterator_new(LookupWhat what) {
*i = (UserDBIterator) {
.what = what,
- .nss_lock = -1,
};
return i;
}
+static int userdb_iterator_block_nss_systemd(UserDBIterator *iterator) {
+ int r;
+
+ assert(iterator);
+
+ if (iterator->nss_systemd_blocked)
+ return 0;
+
+ r = userdb_block_nss_systemd(true);
+ if (r < 0)
+ return r;
+
+ iterator->nss_systemd_blocked = true;
+ return 1;
+}
+
struct user_group_data {
JsonVariant *record;
bool incomplete;
@@ -600,13 +618,11 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) {
return r;
}
- if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- /* Make sure the NSS lookup doesn't recurse back to us. (EBUSY is fine here, it just means we
- * already took the lock from our thread, which is totally OK.) */
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
+ if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) {
+ /* Make sure the NSS lookup doesn't recurse back to us. */
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
/* Client-side NSS fallback */
r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
@@ -649,11 +665,9 @@ int userdb_by_uid(uid_t uid, UserDBFlags flags, UserRecord **ret) {
return r;
}
- if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
-
+ if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) {
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
/* Client-side NSS fallback */
r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
@@ -687,9 +701,9 @@ int userdb_all(UserDBFlags flags, UserDBIterator **ret) {
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags);
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
setpwent();
iterator->nss_iterating = true;
@@ -809,10 +823,8 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) {
}
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
-
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
return r;
@@ -855,10 +867,8 @@ int groupdb_by_gid(gid_t gid, UserDBFlags flags, GroupRecord **ret) {
}
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
-
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
return r;
@@ -891,9 +901,9 @@ int groupdb_all(UserDBFlags flags, UserDBIterator **ret) {
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags);
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
setgrent();
iterator->nss_iterating = true;
@@ -992,9 +1002,9 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish;
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
iterator->filter_user_name = strdup(name);
if (!iterator->filter_user_name)
@@ -1035,9 +1045,9 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator **
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish;
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
/* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */
(void) nss_group_record_by_name(name, false, &gr);
@@ -1076,9 +1086,9 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret) {
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish;
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
setgrent();
iterator->nss_iterating = true;
@@ -1215,115 +1225,24 @@ int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret)
return 0;
}
-static int userdb_thread_sockaddr(struct sockaddr_un *ret_sa, socklen_t *ret_salen) {
- static const uint8_t
- k1[16] = { 0x35, 0xc1, 0x1f, 0x41, 0x59, 0xc6, 0xa0, 0xf9, 0x33, 0x4b, 0x17, 0x3d, 0xb9, 0xf6, 0x14, 0xd9 },
- k2[16] = { 0x6a, 0x11, 0x4c, 0x37, 0xe5, 0xa3, 0x8c, 0xa6, 0x93, 0x55, 0x64, 0x8c, 0x93, 0xee, 0xa1, 0x7b };
-
- struct siphash sh;
- uint64_t x, y;
- pid_t tid;
- void *p;
-
- assert(ret_sa);
- assert(ret_salen);
-
- /* This calculates an AF_UNIX socket address in the abstract namespace whose existence works as an
- * indicator whether to emulate NSS records for complex user records that are also available via the
- * varlink protocol. The name of the socket is picked in a way so that:
- *
- * → it is per-thread (by hashing from the TID)
- *
- * → is not guessable for foreign processes (by hashing from the — hopefully secret — AT_RANDOM
- * value every process gets passed from the kernel
- *
- * By using a socket the NSS emulation can be nicely turned off for limited amounts of time only,
- * simply controlled by the lifetime of the fd itself. By using an AF_UNIX socket in the abstract
- * namespace the lock is automatically cleaned up when the process dies abnormally.
- *
- */
-
- p = ULONG_TO_PTR(getauxval(AT_RANDOM));
- if (!p)
- return -EIO;
-
- tid = gettid();
-
- siphash24_init(&sh, k1);
- siphash24_compress(p, 16, &sh);
- siphash24_compress(&tid, sizeof(tid), &sh);
- x = siphash24_finalize(&sh);
-
- siphash24_init(&sh, k2);
- siphash24_compress(p, 16, &sh);
- siphash24_compress(&tid, sizeof(tid), &sh);
- y = siphash24_finalize(&sh);
-
- *ret_sa = (struct sockaddr_un) {
- .sun_family = AF_UNIX,
- };
-
- sprintf(ret_sa->sun_path + 1, "userdb-%016" PRIx64 "%016" PRIx64, x, y);
- *ret_salen = offsetof(struct sockaddr_un, sun_path) + 1 + 7 + 32;
-
- return 0;
-}
-
-int userdb_nss_compat_is_enabled(void) {
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa;
- socklen_t salen;
- int r;
-
- /* Tests whether the NSS compatibility logic is currently turned on for the invoking thread. Returns
- * true if NSS compatibility is turned on, i.e. whether NSS records shall be synthesized from complex
- * user records. */
-
- r = userdb_thread_sockaddr(&sa.un, &salen);
- if (r < 0)
- return r;
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (fd < 0)
- return -errno;
+int userdb_block_nss_systemd(int b) {
+ _cleanup_(dlclosep) void *dl = NULL;
+ int (*call)(bool b);
- /* Try to connect(). This doesn't do anything really, except that it checks whether the socket
- * address is bound at all. */
- if (connect(fd, &sa.sa, salen) < 0) {
- if (errno == ECONNREFUSED) /* the socket is not bound, hence NSS emulation shall be done */
- return true;
+ /* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */
- return -errno;
+ dl = dlopen(ROOTLIBDIR "libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE);
+ if (!dl) {
+ /* If the file isn't installed, don't complain loudly */
+ log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror());
+ return 0;
}
- return false;
-}
-
-int userdb_nss_compat_disable(void) {
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa;
- socklen_t salen;
- int r;
-
- /* Turn off the NSS compatibility logic for the invoking thread. By default NSS records are
- * synthesized for all complex user records looked up via NSS. If this call is invoked this is
- * disabled for the invoking thread, but only for it. A caller that natively supports the varlink
- * user record protocol may use that to turn off the compatibility for NSS lookups. */
-
- r = userdb_thread_sockaddr(&sa.un, &salen);
- if (r < 0)
- return r;
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return -errno;
-
- if (bind(fd, &sa.sa, salen) < 0) {
- if (errno == EADDRINUSE) /* lock already taken, convert this into a recognizable error */
- return -EBUSY;
-
- return -errno;
- }
+ call = (int (*)(bool b)) dlsym(dl, "_nss_systemd_block");
+ if (!call)
+ /* If the file is is installed but lacks the symbol we expect, things are weird, let's complain */
+ return log_debug_errno(SYNTHETIC_ERRNO(ELIBBAD),
+ "Unable to find symbol _nss_systemd_block in libnss_systemd.so.2: %s", dlerror());
- return TAKE_FD(fd);
+ return call(b);
}
diff --git a/src/shared/userdb.h b/src/shared/userdb.h
index 8af31aa86c..2464f54c3e 100644
--- a/src/shared/userdb.h
+++ b/src/shared/userdb.h
@@ -38,5 +38,4 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret);
int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group);
int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret);
-int userdb_nss_compat_is_enabled(void);
-int userdb_nss_compat_disable(void);
+int userdb_block_nss_systemd(int b);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index ad7400bacc..681992b7e5 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -9207,7 +9207,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_parse_environment();
+ log_parse_environment_cli();
log_open();
/* The journal merging logic potentially needs a lot of fds. */
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index edb40850b1..42bcd74b74 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -110,10 +110,6 @@ int sd_network_link_get_network_file(int ifindex, char **filename);
* IP addresses */
int sd_network_link_get_dns(int ifindex, char ***ret);
-/* Get DHCP4 address for a given link. This is string representations of
- * IPv4 address */
-int sd_network_link_get_dhcp4_address(int ifindex, char **ret);
-
/* Get NTP entries for a given link. These are domain names or string
* representations of IP addresses */
int sd_network_link_get_ntp(int ifindex, char ***ret);
@@ -173,12 +169,6 @@ int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes);
/* Get the CARRIERS that are bound to current link. */
int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
-/* Get the timezone that was learnt on a specific link. */
-int sd_network_link_get_timezone(int ifindex, char **timezone);
-
-/* Get DHCPv4 client id for a given link. */
-int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id);
-
/* Get DHCPv6 client IAID for a given link. */
int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid);
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 6fbd5985d3..b5e7e08eee 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -1898,7 +1898,7 @@ static int run(int argc, char *argv[]) {
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "SELinux setup failed: %m");
+ return r;
/* If command line arguments are specified along with --replace, read all
* configuration files and insert the positional arguments at the specified
diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c
index 0b7dd8764f..f7b3dd5e00 100644
--- a/src/test/test-chase-symlinks.c
+++ b/src/test/test-chase-symlinks.c
@@ -84,9 +84,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char **argv) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index f2bfc6c62b..d0b4ec2764 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -152,6 +152,10 @@ static void test_protect_kernel_logs(void) {
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
0,
NULL);
assert_se(r == 0);
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index cf8b08ba9b..ba2c2ed53b 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -76,6 +76,10 @@ int main(int argc, char *argv[]) {
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
0,
NULL);
if (r < 0) {
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 3f34a91a7e..285eba802b 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -1052,9 +1052,7 @@ static int run(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index da59dd3314..afe593ff64 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -377,7 +377,10 @@ static int context_write_data_local_rtc(Context *c) {
}
}
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
+
return write_string_file_atomic_label("/etc/adjtime", w);
}
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 7938cb3d73..7ad6f13b66 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -3258,7 +3258,9 @@ static int run(int argc, char *argv[]) {
umask(0022);
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
items = ordered_hashmap_new(&item_array_hash_ops);
globs = ordered_hashmap_new(&item_array_hash_ops);
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index f1115bff7a..e476f88f00 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -124,7 +124,10 @@ static int run(int argc, char *argv[]) {
log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
+
return udevadm_main(argc, argv);
}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index d86c1484c3..8db19e4f89 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1863,7 +1863,7 @@ int run_udevd(int argc, char *argv[]) {
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "Could not initialize labelling: %m");
+ return r;
r = mkdir_errno_wrapper("/run/udev", 0755);
if (r < 0 && r != -EEXIST)
diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c
index bbd14165d5..c001802dc9 100644
--- a/src/update-done/update-done.c
+++ b/src/update-done/update-done.c
@@ -49,10 +49,8 @@ int main(int argc, char *argv[]) {
}
r = mac_selinux_init();
- if (r < 0) {
- log_error_errno(r, "SELinux setup failed: %m");
+ if (r < 0)
return EXIT_FAILURE;
- }
r = apply_timestamp("/etc/.updated", &st.st_mtim);
q = apply_timestamp("/var/.updated", &st.st_mtim);
diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c
index c241429517..cd92b696c0 100644
--- a/src/user-sessions/user-sessions.c
+++ b/src/user-sessions/user-sessions.c
@@ -25,7 +25,9 @@ static int run(int argc, char *argv[]) {
umask(0022);
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
if (streq(argv[1], "start")) {
r = unlink_or_warn("/run/nologin");
diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c
index 4b5eb34ca6..648eacd023 100644
--- a/src/userdb/userdbctl.c
+++ b/src/userdb/userdbctl.c
@@ -761,9 +761,7 @@ static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c
index 732063f6c7..d7202099be 100644
--- a/src/userdb/userwork.c
+++ b/src/userdb/userwork.c
@@ -660,7 +660,6 @@ static int process_connection(VarlinkServer *server, int fd) {
static int run(int argc, char *argv[]) {
usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY;
_cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
- _cleanup_close_ int lock = -1;
unsigned n_iterations = 0;
int m, listen_fd, r;
@@ -697,8 +696,8 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m");
listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC;
- lock = userdb_nss_compat_disable();
- if (lock < 0)
+ r = userdb_block_nss_systemd(true);
+ if (r < 0)
return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m");
start_time = now(CLOCK_MONOTONIC);
diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c
index 6d10d7052b..0d33c70401 100644
--- a/src/xdg-autostart-generator/xdg-autostart-service.c
+++ b/src/xdg-autostart-generator/xdg-autostart-service.c
@@ -496,7 +496,7 @@ int xdg_autostart_service_generate_unit(
/* Nothing to do if type is not Application. */
if (!streq_ptr(service->type, "Application")) {
- log_info("Not generating service for XDG autostart %s, it is hidden.", service->name);
+ log_info("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name);
return 0;
}
@@ -527,8 +527,9 @@ int xdg_autostart_service_generate_unit(
return 0;
}
- if (streq_ptr(service->gnome_autostart_phase, "EarlyInitialization")) {
- log_info("Not generating service for XDG autostart %s, EarlyInitialization needs to be handled separately.",
+ if (service->gnome_autostart_phase) {
+ /* There is no explicit value for the "Application" phase. */
+ log_info("Not generating service for XDG autostart %s, startup phases are not supported.",
service->name);
return 0;
}
@@ -563,10 +564,7 @@ int xdg_autostart_service_generate_unit(
fprintf(f, "Description=%s\n", t);
}
- /* Only start after the session is ready.
- * XXX: GNOME has an autostart order which we may want to support.
- * It is not clear how this can be implemented reliably, which
- * is why it is skipped for now. */
+ /* Only start after the session is ready. */
fprintf(f,
"After=graphical-session.target\n");
diff --git a/test/TEST-21-SYSUSERS/test.sh b/test/TEST-21-SYSUSERS/test.sh
index 527db85b07..2992beaa0b 100755
--- a/test/TEST-21-SYSUSERS/test.sh
+++ b/test/TEST-21-SYSUSERS/test.sh
@@ -115,9 +115,7 @@ test_run() {
echo "*** Running test $f"
prepare_testdir ${f%.input}
cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
- systemd-sysusers --root=$TESTDIR 2> /dev/null
- journalctl --sync
- journalctl -t systemd-sysusers -o cat | tail -n1 > $TESTDIR/tmp/err
+ systemd-sysusers --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/tmp/err
if ! diff -u $TESTDIR/tmp/err ${f%.*}.expected-err; then
echo "**** Unexpected error output for $f"
cat $TESTDIR/tmp/err
diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile b/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile
new file mode 100644
index 0000000000..a48af97793
--- /dev/null
+++ b/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile
@@ -0,0 +1,16 @@
+BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
+
+all setup run clean clean-again:
+ @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
+
+# finish option is used to run checks that can only be run outside of
+# the test execution. Example case, honor first shutdown, proof is obtained
+# from the console output as the image shuts down. This does not show up in
+# the journal so the output from the do_test is captured in a file in /tmp.
+# Without the use of finish the test will still pass because if it fails
+# the test will loop and will be terminated via a command timeout.
+# This just provides concrete confirmation.
+finish:
+ @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./fini.sh --$@
+
+.PHONY: all setup run clean clean-again
diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/fini.sh b/test/TEST-52-HONORFIRSTSHUTDOWN/fini.sh
new file mode 100755
index 0000000000..993ada020e
--- /dev/null
+++ b/test/TEST-52-HONORFIRSTSHUTDOWN/fini.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+TEST_DESCRIPTION="test honor first shutdown"
+
+if grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log; then
+ echo "$TEST_DESCRIPTION [pass]"
+ exit 0
+else
+ echo "$TEST_DESCRIPTION [fail]"
+ exit 1
+fi
diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh b/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh
new file mode 100755
index 0000000000..a0848ef672
--- /dev/null
+++ b/test/TEST-52-HONORFIRSTSHUTDOWN/test.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+set -e
+. $TEST_BASE_DIR/test-functions
+TEST_REQUIRE_INSTALL_TESTS=0
+TEST_DESCRIPTION="testing honor first shutdown"
+#INTERACTIVE_DEBUG=1
+TEST_NO_QEMU=1
+
+#Using timeout because if the test fails it can loop.
+# The reason is because the poweroff executed by end.service
+# could turn into a reboot if the test fails.
+NSPAWN_TIMEOUT=20
+
+#Remove this file if it exists. this is used along with
+# the make target "finish". Since concrete confirmaion is
+# only found from the console during the poweroff.
+rm -f /tmp/honorfirstshutdown.log >/dev/null
+
+do_test "$@" 52 > /tmp/honorfirstshutdown.log
diff --git a/test/fuzz/fuzz-bus-message/zero-offset-to-null-pointer b/test/fuzz/fuzz-bus-message/zero-offset-to-null-pointer
new file mode 100644
index 0000000000..c1380441ed
--- /dev/null
+++ b/test/fuzz/fuzz-bus-message/zero-offset-to-null-pointer
Binary files differ
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index 7435d7abec..492d2a033b 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -196,6 +196,8 @@ ReusePort=
RootDirectory=
RootDirectoryStartOnly=
RootImage=
+RootHash=
+RootVerity=
RuntimeMaxSec=
SELinuxContextFromNet=
SecureBits=
diff --git a/test/meson.build b/test/meson.build
index 404b923467..8bda38a2e2 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -28,6 +28,8 @@ install_subdir('testsuite-28.units',
install_dir : testdata_dir)
install_subdir('testsuite-30.units',
install_dir : testdata_dir)
+install_subdir('testsuite-52.units',
+ install_dir : testdata_dir)
testsuite08_dir = testdata_dir + '/testsuite-08.units'
install_data('testsuite-08.units/-.mount',
diff --git a/test/test-functions b/test/test-functions
index df87261ea2..f7f604aec3 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -935,7 +935,7 @@ install_config_files() {
inst /etc/login.defs
inst /etc/group
inst /etc/shells
- inst /etc/nsswitch.conf
+ inst_any /etc/nsswitch.conf /usr/etc/nsswitch.conf
inst /etc/pam.conf || :
inst /etc/os-release
inst /etc/localtime
diff --git a/test/testsuite-52.units/testsuite-52.service b/test/testsuite-52.units/testsuite-52.service
new file mode 100755
index 0000000000..93f847f044
--- /dev/null
+++ b/test/testsuite-52.units/testsuite-52.service
@@ -0,0 +1,6 @@
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/usr/lib/systemd/tests/testdata/%N.units/%N.sh
+Type=oneshot
diff --git a/test/testsuite-52.units/testsuite-52.sh b/test/testsuite-52.units/testsuite-52.sh
new file mode 100755
index 0000000000..9cccf1b6c1
--- /dev/null
+++ b/test/testsuite-52.units/testsuite-52.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+set -ex
+set -o pipefail
+
+if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then
+ echo "honor-first-shutdown script not found - FAIL" > /testok
+ exit 0
+fi
+
+systemd-analyze log-level debug
+systemd-analyze log-target console
+
+systemctl enable test-honor-first-shutdown.service
+systemctl start test-honor-first-shutdown.service
+
+echo OK > /testok
+
+exit 0
diff --git a/test/units/test-honor-first-shutdown.service b/test/units/test-honor-first-shutdown.service
new file mode 100644
index 0000000000..374f1e6b5f
--- /dev/null
+++ b/test/units/test-honor-first-shutdown.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Honor First Shutdown feature
+After=multi-user.target
+
+[Service]
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
+ExecStop=sh -c 'kill -SIGKILL $MAINPID'
+FailureAction=reboot
+
+[Install]
+WantedBy=multi-user.target \ No newline at end of file
diff --git a/test/units/test-honor-first-shutdown.sh b/test/units/test-honor-first-shutdown.sh
new file mode 100755
index 0000000000..17c1ec9686
--- /dev/null
+++ b/test/units/test-honor-first-shutdown.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+echo "Honor first shutdown test script"
+sleep infinity;
diff --git a/tools/make-autosuspend-rules.py b/tools/make-autosuspend-rules.py
index 25b261ea0d..e13ca33f6f 100755
--- a/tools/make-autosuspend-rules.py
+++ b/tools/make-autosuspend-rules.py
@@ -1,14 +1,24 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+
-# Generate autosuspend rules for devices that have been whitelisted (IE tested)
-# by the Chromium OS team. Please keep this script in sync with:
+# Generate autosuspend rules for devices that have been tested to work properly
+# with autosuspend by the Chromium OS team. Based on
# https://chromium.googlesource.com/chromiumos/platform2/+/master/power_manager/udev/gen_autosuspend_rules.py
-import sys
import chromiumos.gen_autosuspend_rules
-if __name__ == '__main__':
- if len(sys.argv) > 1:
- sys.stdout = open(sys.argv[1], 'w')
- chromiumos.gen_autosuspend_rules.main()
+print('# pci:v<00VENDOR>d<00DEVICE> (8 uppercase hexadecimal digits twice)')
+for entry in chromiumos.gen_autosuspend_rules.PCI_IDS:
+ vendor, device = entry.split(':')
+ vendor = int(vendor, 16)
+ device = int(device, 16)
+ print('pci:v{:08X}d{:08X}*'.format(vendor, device))
+
+print('# usb:v<VEND>p<PROD> (4 uppercase hexadecimal digits twice')
+for entry in chromiumos.gen_autosuspend_rules.USB_IDS:
+ vendor, product = entry.split(':')
+ vendor = int(vendor, 16)
+ product = int(product, 16)
+ print('usb:v{:04X}p{:04X}*'.format(vendor, product))
+
+print(' ID_AUTOSUSPEND=1')
diff --git a/travis-ci/managers/debian.sh b/travis-ci/managers/debian.sh
index 60f6237606..a2a987d8fd 100755
--- a/travis-ci/managers/debian.sh
+++ b/travis-ci/managers/debian.sh
@@ -9,23 +9,25 @@
# export CONT_NAME="my-fancy-container"
# travis-ci/managers/debian.sh SETUP RUN CLEANUP
-PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
+PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
-CONT_NAME="${CONT_NAME:-debian-$DEBIAN_RELEASE-$RANDOM}"
+CONT_NAME="${CONT_NAME:-systemd-debian-$DEBIAN_RELEASE}"
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
DOCKER_RUN="${DOCKER_RUN:-docker run}"
REPO_ROOT="${REPO_ROOT:-$PWD}"
-ADDITIONAL_DEPS=(python3-libevdev
- python3-pyparsing
- clang
- perl
- libpwquality-dev
- fdisk
- libfdisk-dev
- libp11-kit-dev
- libssl-dev
- libzstd-dev
- zstd)
+ADDITIONAL_DEPS=(
+ clang
+ fdisk
+ libfdisk-dev
+ libp11-kit-dev
+ libpwquality-dev
+ libssl-dev
+ libzstd-dev
+ perl
+ python3-libevdev
+ python3-pyparsing
+ zstd
+)
function info() {
echo -e "\033[33;1m$1\033[0m"
@@ -54,7 +56,7 @@ for phase in "${PHASES[@]}"; do
$DOCKER_EXEC apt-get -y build-dep systemd
$DOCKER_EXEC apt-get -y install "${ADDITIONAL_DEPS[@]}"
;;
- RUN|RUN_CLANG)
+ RUN|RUN_GCC|RUN_CLANG)
if [[ "$phase" = "RUN_CLANG" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
fi
@@ -62,8 +64,8 @@ for phase in "${PHASES[@]}"; do
$DOCKER_EXEC ninja -v -C build
docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test
;;
- RUN_ASAN|RUN_CLANG_ASAN)
- if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+ RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
+ if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
# Build fuzzer regression tests only with clang (for now),
# see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604
diff --git a/travis-ci/managers/fedora.sh b/travis-ci/managers/fedora.sh
index b3c85ebd09..cc665021d4 100755
--- a/travis-ci/managers/fedora.sh
+++ b/travis-ci/managers/fedora.sh
@@ -9,38 +9,32 @@
# export CONT_NAME="my-fancy-container"
# travis-ci/managers/fedora.sh SETUP RUN CLEANUP
-PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
+PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
FEDORA_RELEASE="${FEDORA_RELEASE:-rawhide}"
-CONT_NAME="${CONT_NAME:-fedora-$FEDORA_RELEASE-$RANDOM}"
+CONT_NAME="${CONT_NAME:-systemd-fedora-$FEDORA_RELEASE}"
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
DOCKER_RUN="${DOCKER_RUN:-docker run}"
REPO_ROOT="${REPO_ROOT:-$PWD}"
-ADDITIONAL_DEPS=(dnf-plugins-core
- jq iputils
- hostname libasan
- python3-pyparsing
- python3-evdev
- libubsan
- clang
- llvm
- perl
- libfdisk-devel
- libpwquality-devel
- openssl-devel
- p11-kit-devel)
+ADDITIONAL_DEPS=(
+ clang
+ dnf-plugins-core
+ hostname libasan
+ jq iputils
+ libfdisk-devel
+ libpwquality-devel
+ libubsan
+ llvm
+ openssl-devel
+ p11-kit-devel
+ perl
+ python3-evdev
+ python3-pyparsing
+)
info() {
echo -e "\033[33;1m$1\033[0m"
}
-error() {
- echo >&2 -e "\033[31;1m$1\033[0m"
-}
-
-success() {
- echo >&2 -e "\033[32;1m$1\033[0m"
-}
-
# Simple wrapper which retries given command up to five times
_retry() {
local EC=1
@@ -94,8 +88,8 @@ for phase in "${PHASES[@]}"; do
$DOCKER_EXEC ninja -v -C build
$DOCKER_EXEC ninja -C build test
;;
- RUN_ASAN|RUN_CLANG_ASAN)
- if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+ RUN_ASAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
+ if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
fi
@@ -110,46 +104,6 @@ for phase in "${PHASES[@]}"; do
-t $CONT_NAME \
meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
;;
- RUN_BUILD_CHECK_GCC|RUN_BUILD_CHECK_CLANG)
- ARGS=(
- "--optimization=0"
- "--optimization=2"
- "--optimization=3"
- "--optimization=s"
- "-Db_lto=true"
- "-Db_ndebug=true"
- )
-
- if [[ "$phase" = "RUN_BUILD_CHECK_CLANG" ]]; then
- ENV_VARS="-e CC=clang -e CXX=clang++"
- $DOCKER_EXEC clang --version
- else
- $DOCKER_EXEC gcc --version
- fi
-
- for args in "${ARGS[@]}"; do
- SECONDS=0
- info "Checking build with $args"
- # Redirect meson/ninja logs into separate files, otherwise we
- # would trip over Travis' log size limit
- if ! docker exec $ENV_VARS -it $CONT_NAME meson --werror $args build &> meson.log; then
- cat meson.log
- error "meson failed with $args"
- exit 1
- fi
-
- if ! $DOCKER_EXEC ninja -v -C build &> ninja.log; then
- cat ninja.log
- error "ninja failed with $args"
- exit 1
- fi
-
- $DOCKER_EXEC rm -fr build
- rm -f meson.log ninja.log
- success "Build with $args passed in $SECONDS seconds"
- done
-
- ;;
CLEANUP)
info "Cleanup phase"
docker stop $CONT_NAME